コード例 #1
0
ファイル: emulation.cpp プロジェクト: yunxiaoxiao110/haiku
/*! Emulate REQUEST SENSE */
void
ide_request_sense(ide_device_info *device, ide_qrequest *qrequest)
{
    scsi_ccb *request = qrequest->request;
    scsi_cmd_request_sense *cmd = (scsi_cmd_request_sense *)request->cdb;
    scsi_sense sense;
    uint32 transferSize;

    // cannot use finish_checksense here, as data is not copied into autosense buffer
    // but into normal data buffer, SCSI result is GOOD and CAM status is REQ_CMP

    if (device->combined_sense)
        create_sense(device, &sense);
    else
        memset(&sense, 0, sizeof(sense));

    copy_sg_data(request, 0, cmd->allocation_length, &sense, sizeof(sense), false);

    // reset sense information on read
    device->combined_sense = 0;

    transferSize = min_c(sizeof(sense), cmd->allocation_length);
    transferSize = min_c(transferSize, request->data_length);

    request->data_resid = request->data_length - transferSize;

    // normally, all flags are set to "success", but for Request Sense
    // this would have overwritten the sense we want to read
    device->subsys_status = SCSI_REQ_CMP;
    request->device_status = SCSI_STATUS_GOOD;
}
コード例 #2
0
ファイル: scsi2ata.c プロジェクト: luciang/haiku
/*! Emulate INQUIRY command */
static void
ata_inquiry(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	scsi_res_inquiry data;
	scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb;
	uint32 allocation_length = cmd->allocation_length;
	uint32 transfer_size;

	if (cmd->evpd || cmd->page_code) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
		return;
	}

	memset(&data, 0, sizeof(data));

	data.device_type = scsi_dev_direct_access;
	data.device_qualifier = scsi_periph_qual_connected;

	data.device_type_modifier = 0;
	data.removable_medium = false;

	data.ansi_version = 2;
	data.ecma_version = 0;
	data.iso_version = 0;

	data.response_data_format = 2;
	data.term_iop = false;
		// to be changed if we support TERM I/O

	data.additional_length = sizeof(scsi_res_inquiry) - 4;

	data.soft_reset = false;
	data.cmd_queue = device->queue_depth > 1;
	data.linked = false;

	// these values are free-style
	data.sync = false;
	data.write_bus16 = true;
	data.write_bus32 = false;

	data.relative_address = false;

	// the following fields are *much* to small, sigh...
	memcpy(data.vendor_ident, device->infoblock.model_number, 
		sizeof(data.vendor_ident));
	memcpy(data.product_ident, device->infoblock.model_number + 8, 
		sizeof(data.product_ident));
	memcpy(data.product_rev, "    ", sizeof(data.product_rev));

	copy_sg_data(request, 0, allocation_length, &data, sizeof(data), false);

	transfer_size = min(sizeof(data), allocation_length);
	transfer_size = min(transfer_size, request->data_length);

	request->data_resid = request->data_length - transfer_size;
}
コード例 #3
0
ファイル: VirtioSCSIRequest.cpp プロジェクト: DonCN/haiku
void
VirtioSCSIRequest::RequestSense()
{
	CALLED();
	// Copy sense data from last request into data buffer of current request.
	// The sense data of last request is still present in the current request,
	// as it isn't cleared on SCSI_OP_REQUEST_SENSE.
	scsi_cmd_request_sense *command = (scsi_cmd_request_sense *)fCCB->cdb;
	copy_sg_data(fCCB, 0, command->allocation_length, fResponse->sense,
		fResponse->sense_len, false);

	fCCB->data_resid = fCCB->data_length - min_c(min_c(fResponse->sense_len,
		command->allocation_length), fCCB->data_length);
	fResponse->sense_len = 0;
}
コード例 #4
0
ファイル: scsi2ata.c プロジェクト: luciang/haiku
/*! Emulate READ CAPACITY command */
static void
read_capacity(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	scsi_res_read_capacity data;
	scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cdb;
	uint32 lastBlock;

	if (cmd->pmi || cmd->lba) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
		return;
	}

	// TODO: 512 bytes fixed block size?
	data.block_size = B_HOST_TO_BENDIAN_INT32(512);

	lastBlock = device->total_sectors - 1;
	data.lba = B_HOST_TO_BENDIAN_INT32(lastBlock);

	copy_sg_data(request, 0, request->data_length, &data, sizeof(data), false);
	request->data_resid = max(request->data_length - sizeof(data), 0);
}
コード例 #5
0
ファイル: scsi2ata.c プロジェクト: luciang/haiku
static void
ata_mode_sense_10(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	scsi_cmd_mode_sense_10 *cmd = (scsi_cmd_mode_sense_10 *)request->cdb;
	scsi_mode_param_header_10 param_header;
	scsi_modepage_control control;
	scsi_mode_param_block_desc block_desc;
	size_t totalLength = sizeof(scsi_mode_param_header_10)
		+ sizeof(scsi_mode_param_block_desc)
		+ sizeof(scsi_modepage_control);
	scsi_mode_param_dev_spec_da devspec = {
		_res0_0 : 0,
		dpo_fua : 0,
		_res0_6 : 0,
		write_protected : 0
	};
	uint32 allocationLength;

	SHOW_FLOW0(1, "Hi!");

	allocationLength = B_BENDIAN_TO_HOST_INT16(cmd->allocation_length);

	// we answer control page requests and "all pages" requests
	// (as the latter are the same as the first)
	if ((cmd->page_code != SCSI_MODEPAGE_CONTROL && cmd->page_code != SCSI_MODEPAGE_ALL)
		|| (cmd->page_control != SCSI_MODE_SENSE_PC_CURRENT
			&& cmd->page_control != SCSI_MODE_SENSE_PC_SAVED)) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
		return;
	}

	//param_header = (scsi_mode_param_header_10 *)request->data;
	param_header.mode_data_length = B_HOST_TO_BENDIAN_INT16(totalLength - 1);
	param_header.medium_type = 0; 		// XXX standard is a bit vague here
	param_header.dev_spec_parameter = *(uint8 *)&devspec;
	param_header.block_desc_length
		= B_HOST_TO_BENDIAN_INT16(sizeof(scsi_mode_param_block_desc));

	copy_sg_data(request, 0, allocationLength, &param_header,
		sizeof(param_header), false);

	/*block_desc = (scsi_mode_param_block_desc *)(request->data 
		+ sizeof(*param_header));*/
	memset(&block_desc, 0, sizeof(block_desc));
	// density is reserved (0), descriptor apply to entire medium (num_blocks=0)
	// remains the blocklen to be set
	block_desc.high_blocklen = 0;
	block_desc.med_blocklen = 512 >> 8;
	block_desc.low_blocklen = 512 & 0xff;

	copy_sg_data(request, sizeof(param_header), allocationLength,
		&block_desc, sizeof(block_desc), false);

	/*contr = (scsi_modepage_contr *)(request->data 
		+ sizeof(*param_header)
		+ ((uint16)param_header->high_block_desc_len << 8) 
		+ param_header->low_block_desc_len);*/

	memset(&control, 0, sizeof(control));
	control.RLEC = false;
	control.DQue = !device->CQ_enabled;
	control.QErr = false;
		// when a command fails we requeue all 
		// lost commands automagically
	control.QAM = SCSI_QAM_UNRESTRICTED;

	copy_sg_data(request, sizeof(param_header)
		+ B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length),
		allocationLength, &control, sizeof(control), false);

	// the number of bytes that were transferred to buffer is
	// restricted by allocation length and by request data buffer size
	totalLength = min(totalLength, allocationLength);
	totalLength = min(totalLength, request->data_length);

	request->data_resid = request->data_length - totalLength;
}


/*! Emulate modifying control page */
static bool
ata_mode_select_control_page(ide_device_info *device, ide_qrequest *qrequest,
	scsi_modepage_control *page)
{
	if (page->header.page_length != sizeof(*page) - sizeof(page->header)) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR);
		return false;
	}

	// we only support enabling/disabling command queuing
	enable_CQ(device, !page->DQue);
	return true;
}


/*! Emulate MODE SELECT 10 command */
static void
ata_mode_select_10(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	scsi_cmd_mode_select_10 *cmd = (scsi_cmd_mode_select_10 *)request->cdb;
	scsi_mode_param_header_10 param_header;
	scsi_modepage_header page_header;
	uint32 totalLength;
	uint32 modepageOffset;
	char modepage_buffer[64];	// !!! enlarge this to support longer mode pages

	if (cmd->save_pages || cmd->pf != 1) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
		return;
	}

	totalLength = min(request->data_length,
		B_BENDIAN_TO_HOST_INT16(cmd->param_list_length));

	// first, retrieve page header to get size of different chunks
	//param_header = (scsi_mode_param_header_10 *)request->data;
	if (!copy_sg_data(request, 0, totalLength, &param_header, sizeof(param_header), true))
		goto err;

	totalLength = min(totalLength,
		B_BENDIAN_TO_HOST_INT16(param_header.mode_data_length) + 1UL);

	// this is the start of the first mode page;
	// we ignore the block descriptor silently
	modepageOffset = sizeof(param_header)
		+ B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length);

	// go through list of pages		
	while (modepageOffset < totalLength) {
		uint32 pageLength;

		// get header to know how long page is
		if (!copy_sg_data(request, modepageOffset, totalLength,
				&page_header, sizeof(page_header), true))
			goto err;

		// get size of one page and copy it to buffer
		pageLength = page_header.page_length + sizeof(scsi_modepage_header);

		// the buffer has a maximum size - this is really standard compliant but
		// sufficient for our needs
		if (pageLength > sizeof(modepage_buffer))
			goto err;

		if (!copy_sg_data(request, modepageOffset, totalLength,
				&modepage_buffer, min(pageLength, sizeof(modepage_buffer)), true))
			goto err;

		// modify page;
		// currently, we only support the control mode page
		switch (page_header.page_code) {
			case SCSI_MODEPAGE_CONTROL:
				if (!ata_mode_select_control_page(device, qrequest,
						(scsi_modepage_control *)modepage_buffer))
					return;
				break;

			default:
				set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST,
					SCSIS_ASC_INV_PARAM_LIST_FIELD);
				return;
		}

		modepageOffset += pageLength;
	}

	if (modepageOffset != totalLength)
		goto err;

	request->data_resid = request->data_length - totalLength;
	return;

	// if we arrive here, data length was incorrect
err:
	set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR);
}