コード例 #1
0
ファイル: removable.cpp プロジェクト: mmanley/Antares
/*!	Send START/STOP command to device
	start - true for start, false for stop
	withLoadEject - if true, then lock drive on start and eject on stop
*/
err_res
periph_send_start_stop(scsi_periph_device_info *device, scsi_ccb *request,
	bool start, bool withLoadEject)
{
	scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cdb;

	// this must be ordered, so all previous commands are really finished
	request->flags = SCSI_DIR_NONE | SCSI_ORDERED_QTAG;

	request->data = NULL;
	request->sg_list = NULL;
	request->data_length = 0;
	request->timeout = device->std_timeout;
	request->sort = -1;
	request->sg_list = NULL;

	memset(cmd, 0, sizeof(*cmd));
	cmd->opcode = SCSI_OP_START_STOP;
	// we don't want to poll; we give a long timeout instead
	// (well - the default timeout _is_ large)
	cmd->immediately = 0;
	cmd->start = start;
	cmd->load_eject = withLoadEject;

	request->cdb_length = sizeof(*cmd);

	device->scsi->sync_io(request);

	return periph_check_error(device, request);
}
コード例 #2
0
ファイル: sync.cpp プロジェクト: AmirAbrams/haiku
err_res
periph_synchronize_cache(scsi_periph_device_info *device, scsi_ccb *request)
{
	scsi_cmd_sync_cache* cmd = (scsi_cmd_sync_cache*)request->cdb;
	
	request->flags = SCSI_DIR_NONE;
	
	request->data = NULL;
	request->sg_list = NULL;
	request->data_length = 0;
	request->timeout = device->std_timeout;
	request->sort = -1;
	
	memset(cmd, 0, sizeof(*cmd));
	
	cmd->opcode	= SCSI_OP_SYNCHRONIZE_CACHE;
	cmd->immediately = 0;
	
	// TODO: Maybe we will actually want to set this one day...
	cmd->block_count = 0;
	
	request->cdb_length = sizeof(*cmd);
	
	device->scsi->sync_io(request);

	return periph_check_error(device, request);
}
コード例 #3
0
ファイル: scsi_periph.cpp プロジェクト: AmirAbrams/haiku
status_t
periph_safe_exec(scsi_periph_device_info *device, scsi_ccb *request)
{
	err_res res;
	int retries = 0;

	do {
		device->scsi->sync_io(request);

		// ask generic peripheral layer what to do now
		res = periph_check_error(device, request);
		if (res.action == err_act_start) {
			// backup request, as we need it temporarily for sending "start"
			// (we cannot allocate a new cdb as there may be no more cdb and
			//  waiting for one to become empty may lead to deadlock if everyone
			//  does that)
			uint32 backup_flags;
			uint8 backup_cdb[SCSI_MAX_CDB_SIZE];
			uchar backup_cdb_len;
			int64 backup_sort;
			bigtime_t backup_timeout;
			uchar *backup_data;
			const physical_entry *backup_sg_list;
			uint16 backup_sg_count;
			uint32 backup_data_len;

			backup_flags = request->flags;
			memcpy(backup_cdb, request->cdb, SCSI_MAX_CDB_SIZE);
			backup_cdb_len = request->cdb_length;
			backup_sort = request->sort;
			backup_timeout = request->timeout;
			backup_data = request->data;
			backup_sg_list = request->sg_list;
			backup_sg_count = request->sg_count;
			backup_data_len = request->data_length;

			SHOW_INFO0( 2, "Sending start to init LUN" );

			res = periph_send_start_stop(device, request, 1, device->removable);

			request->flags = backup_flags;
			memcpy(request->cdb, backup_cdb, SCSI_MAX_CDB_SIZE);
			request->cdb_length = backup_cdb_len;
			request->sort = backup_sort;
			request->timeout = backup_timeout;
			request->data = backup_data;
			request->sg_list = backup_sg_list;
			request->sg_count = backup_sg_count;
			request->data_length = backup_data_len;

			if (res.action == err_act_ok)
				res.action = err_act_retry;
		}
	} while ((res.action == err_act_retry && retries++ < 3)
		|| (res.action == err_act_many_retries && retries++ < 30));

	return res.error_code;
}
コード例 #4
0
ファイル: removable.cpp プロジェクト: mmanley/Antares
static err_res
send_tur(scsi_periph_device_info *device, scsi_ccb *request)
{
	scsi_cmd_tur *cmd = (scsi_cmd_tur *)request->cdb;

	request->flags = SCSI_DIR_NONE | SCSI_ORDERED_QTAG;

	request->data = NULL;
	request->sg_list = NULL;
	request->data_length = 0;
	request->timeout = device->std_timeout;
	request->sort = -1;
	request->sg_list = NULL;

	memset(cmd, 0, sizeof(*cmd));
	cmd->opcode = SCSI_OP_TEST_UNIT_READY;

	request->cdb_length = sizeof(*cmd);

	device->scsi->sync_io(request);

	return periph_check_error(device, request);
}
コード例 #5
0
ファイル: io.cpp プロジェクト: DonCN/haiku
/*! Universal read/write function */
static status_t
read_write(scsi_periph_device_info *device, scsi_ccb *request,
	io_operation *operation, uint64 offset, size_t originalNumBlocks,
	physical_entry* vecs, size_t vecCount, bool isWrite,
	size_t* _bytesTransferred)
{
	uint32 blockSize = device->block_size;
	size_t numBlocks = originalNumBlocks;
	uint32 pos = offset;
	err_res res;
	int retries = 0;

	do {
		size_t numBytes;
		bool isReadWrite10 = false;

		request->flags = isWrite ? SCSI_DIR_OUT : SCSI_DIR_IN;

		// io_operations are generated by a DMAResource and thus contain DMA
		// safe physical vectors
		if (operation != NULL)
			request->flags |= SCSI_DMA_SAFE;

		// make sure we avoid 10 byte commands if they aren't supported
		if (!device->rw10_enabled || device->preferred_ccb_size == 6) {
			// restricting transfer is OK - the block manager will
			// take care of transferring the rest
			if (numBlocks > 0x100)
				numBlocks = 0x100;

			// no way to break the 21 bit address limit
			if (offset > 0x200000)
				return B_BAD_VALUE;

			// don't allow transfer cross the 24 bit address limit
			// (I'm not sure whether this is allowed, but this way we
			// are sure to not ask for trouble)
			if (offset < 0x100000)
				numBlocks = min_c(numBlocks, 0x100000 - pos);
		}

		numBytes = numBlocks * blockSize;
		if (numBlocks != originalNumBlocks)
			panic("I/O operation would need to be cut.");

		request->data = NULL;
		request->sg_list = vecs;
		request->data_length = numBytes;
		request->sg_count = vecCount;
		request->io_operation = operation;
		request->sort = pos;
		request->timeout = device->std_timeout;
		// see whether daemon instructed us to post an ordered command;
		// reset flag after read
		SHOW_FLOW(3, "flag=%x, next_tag=%x, ordered: %s",
			(int)request->flags, (int)device->next_tag_action,
			(request->flags & SCSI_ORDERED_QTAG) != 0 ? "yes" : "no");

		// use shortest commands whenever possible
		if (offset + numBlocks < 0x200000LL && numBlocks <= 0x100) {
			scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;

			isReadWrite10 = false;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_6 : SCSI_OP_READ_6;
			cmd->high_lba = (pos >> 16) & 0x1f;
			cmd->mid_lba = (pos >> 8) & 0xff;
			cmd->low_lba = pos & 0xff;
			cmd->length = numBlocks;

			request->cdb_length = sizeof(*cmd);
		} else if (offset + numBlocks < 0x100000000LL && numBlocks <= 0x10000) {
			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;

			isReadWrite10 = true;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10;
			cmd->relative_address = 0;
			cmd->force_unit_access = 0;
			cmd->disable_page_out = 0;
			cmd->lba = B_HOST_TO_BENDIAN_INT32(pos);
			cmd->length = B_HOST_TO_BENDIAN_INT16(numBlocks);

			request->cdb_length = sizeof(*cmd);
		} else if (offset + numBlocks < 0x100000000LL && numBlocks <= 0x10000000) {
			scsi_cmd_rw_12 *cmd = (scsi_cmd_rw_12 *)request->cdb;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_12 : SCSI_OP_READ_12;
			cmd->relative_address = 0;
			cmd->force_unit_access = 0;
			cmd->disable_page_out = 0;
			cmd->lba = B_HOST_TO_BENDIAN_INT32(pos);
			cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks);

			request->cdb_length = sizeof(*cmd);
		} else {
			scsi_cmd_rw_16 *cmd = (scsi_cmd_rw_16 *)request->cdb;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_16 : SCSI_OP_READ_16;
			cmd->force_unit_access_non_volatile = 0;
			cmd->force_unit_access = 0;
			cmd->disable_page_out = 0;
			cmd->lba = B_HOST_TO_BENDIAN_INT64(offset);
			cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks);

			request->cdb_length = sizeof(*cmd);
		}

		// TODO: last chance to detect errors that occured during concurrent accesses
		//status_t status = handle->pending_error;
		//if (status != B_OK)
		//	return status;

		device->scsi->async_io(request);

		acquire_sem(request->completion_sem);

		// ask generic peripheral layer what to do now
		res = periph_check_error(device, request);

		// TODO: bytes might have been transferred even in the error case!
		switch (res.action) {
			case err_act_ok:
				*_bytesTransferred = numBytes - request->data_resid;
				break;

			case err_act_start:
				res = periph_send_start_stop(device, request, 1,
					device->removable);
				if (res.action == err_act_ok)
					res.action = err_act_retry;
				break;

			case err_act_invalid_req:
				// if this was a 10 byte command, the device probably doesn't
				// support them, so disable them and retry
				if (isReadWrite10) {
					atomic_and(&device->rw10_enabled, 0);
					res.action = err_act_retry;
				} else
					res.action = err_act_fail;
				break;
		}
	} while ((res.action == err_act_retry && retries++ < 3)