コード例 #1
0
ファイル: ata.c プロジェクト: AmirAbrams/haiku
void
ata_dpc_DMA(ide_qrequest *qrequest)
{
	ide_device_info *device = qrequest->device;
	bool dma_success, dev_err;

	dma_success = finish_dma(device);
	dev_err = check_rw_error(device, qrequest);

	if (dma_success && !dev_err) {
		// reset error count if DMA worked
		device->DMA_failures = 0;
		device->CQ_failures = 0;
		qrequest->request->data_resid = 0;
		finish_checksense(qrequest);
	} else {
		SHOW_ERROR0( 2, "Error in DMA transmission" );

		set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_FAILURE);

		if (++device->DMA_failures >= MAX_DMA_FAILURES) {
			SHOW_ERROR0( 2, "Disabled DMA because of too many errors" );
			device->DMA_enabled = false;
		}

		// reset queue in case queuing is active
		finish_reset_queue(qrequest);
	}
}
コード例 #2
0
ファイル: ide_sim.c プロジェクト: HTshandou/newos
static void finish_setsense( ide_device_info *device, ide_qrequest *qrequest, 
	int sense_key, int sense_asc )
{
	set_sense( device, sense_key, sense_asc );

	finish_checksense( qrequest );
}
コード例 #3
0
ファイル: ide_sim.c プロジェクト: HTshandou/newos
void finish_reset_queue( ide_qrequest *qrequest )
{
	ide_bus_info *bus = qrequest->device->bus;
	
	xpt->block_bus( bus->xpt_cookie );

	finish_checksense( qrequest );
	send_abort_queue( qrequest->device );
		
	xpt->unblock_bus( bus->xpt_cookie );
}		
コード例 #4
0
ファイル: ata.c プロジェクト: HTshandou/newos
void ata_dpc_DMA( ide_qrequest *qrequest )
{
	ide_device_info *device = qrequest->device;
	//ide_bus_info *bus = device->bus;
	bool dma_err, dev_err;
	
	dma_err = finish_dma( device );
	dev_err = check_rw_error( device, qrequest );
	
	if( !dma_err && !dev_err ) {
		device->DMA_failures = 0;
		device->CQ_failures = 0;
		qrequest->request->cam_resid = 0;
		finish_checksense( qrequest );
	} else {
		if( ++device->DMA_failures == MAX_DMA_FAILURES ) {
			device->DMA_enabled = false;
			finish_reset_queue( qrequest );
		} else {
			finish_retry( qrequest );
		}
	}
}
コード例 #5
0
ファイル: ata.c プロジェクト: HTshandou/newos
void ata_dpc_PIO( ide_qrequest *qrequest )
{
	ide_device_info *device = qrequest->device;
	bigtime_t timeout = qrequest->request->cam_timeout > 0 ? 
		qrequest->request->cam_timeout : IDE_STD_TIMEOUT;
	
	if( !check_rw_error( device, qrequest ) ||
		!check_rw_status( device, qrequest,
		qrequest->is_write ? device->left_blocks > 1 : true )) 
	{
		/*if( (device->sense.sense_key == SCSIS_KEY_ABORTED_COMMAND ||
			 device->sense.ascq == SCSIS_ASC_UNREC_READ_ERR) &&
			++qrequest->retries < MAX_PIO_RETRIES ) 
		{
			finish_rw_request( qrequest, ide_finish_rw_retry );
		} else*/
			finish_checksense( qrequest );
			
		return;
	}

	if( qrequest->is_write ) {
		if( device->left_blocks == 0 )
			goto finish;
			
		if( !wait_for_drq( device )) 
			goto finish;
			
		start_waiting_nolock( device->bus, timeout, ide_state_async_waiting );
		
		// having a too short data buffer shouldn't happen here
		// anyway - we are prepared
		if( write_PIO_block( qrequest, 512 ) == ERR_GENERAL )
			goto finish_cancel_timeout;
			
		--device->left_blocks;

	} else {
		if( device->left_blocks > 0 )
			start_waiting_nolock( device->bus, timeout, ide_state_async_waiting );
		
		// see write
		if( read_PIO_block( qrequest, 512 ) == ERR_GENERAL ) 
			goto finish_cancel_timeout;
			
		--device->left_blocks;
		
		if( device->left_blocks == 0 ) {
			wait_for_drqdown( device );
			goto finish_cancel_timeout;
		}
	}
	
	//start_waiting( device->bus );
	return;
	
finish_cancel_timeout:
	cancel_irq_timeout( device->bus );
	
finish:
	finish_checksense( qrequest );
	return;
}
コード例 #6
0
ファイル: scsi2ata.c プロジェクト: luciang/haiku
/*! Execute SCSI command */
void
ata_exec_io(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	
	SHOW_FLOW(3, "command=%x", request->cdb[0]);
		
	// ATA devices have one LUN only
	if (request->target_lun != 0) {
		request->subsys_status = SCSI_SEL_TIMEOUT;
		finish_request(qrequest, false);
		return;
	}

	// starting a request means deleting sense, so don't do it if
	// the command wants to read it
	if (request->cdb[0] != SCSI_OP_REQUEST_SENSE)	
		start_request(device, qrequest);

	switch (request->cdb[0]) {
		case SCSI_OP_TEST_UNIT_READY:
			ata_test_unit_ready(device, qrequest);
			break;

		case SCSI_OP_REQUEST_SENSE:
			ide_request_sense(device, qrequest);
			return;

		case SCSI_OP_FORMAT: /* FORMAT UNIT */
			// we could forward request to disk, but modern disks cannot
			// be formatted anyway, so we just refuse request
			// (exceptions are removable media devices, but to my knowledge
			// they don't have to be formatted as well)
			set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
			break;

		case SCSI_OP_INQUIRY: 
			ata_inquiry(device, qrequest);
			break;

		case SCSI_OP_MODE_SELECT_10:
			ata_mode_select_10(device, qrequest);
			break;

		case SCSI_OP_MODE_SENSE_10:
			ata_mode_sense_10(device, qrequest);
			break;

		case SCSI_OP_MODE_SELECT_6:
		case SCSI_OP_MODE_SENSE_6:
			// we've told SCSI bus manager to emulates these commands
			set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
			break;

		case SCSI_OP_RESERVE:
		case SCSI_OP_RELEASE:
			// though mandatory, this doesn't make much sense in a
			// single initiator environment; so what
			set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
			break;

		case SCSI_OP_START_STOP: {
			scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cdb;

			// with no LoEj bit set, we should only allow/deny further access
			// we ignore that (unsupported for ATA)
			// with LoEj bit set, we should additionally either load or eject the medium
			// (start = 0 - eject; start = 1 - load)

			if (!cmd->start)
				// we must always flush cache if start = 0
				ata_flush_cache(device, qrequest);

			if (cmd->load_eject)
				ata_load_eject(device, qrequest, cmd->start);

			break;
		}

		case SCSI_OP_PREVENT_ALLOW: {
			scsi_cmd_prevent_allow *cmd = (scsi_cmd_prevent_allow *)request->cdb;

			ata_prevent_allow(device, cmd->prevent);
			break;
		}

		case SCSI_OP_READ_CAPACITY:
			read_capacity(device, qrequest);
			break;

		case SCSI_OP_VERIFY:
			// does anyone uses this function?
			// effectly, it does a read-and-compare, which IDE doesn't support
			set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
			break;

		case SCSI_OP_SYNCHRONIZE_CACHE:
			// we ignore range and immediate bit, we always immediately flush everything 
			ata_flush_cache(device, qrequest);
			break;

		// sadly, there are two possible read/write operation codes;
		// at least, the third one, read/write(12), is not valid for DAS
		case SCSI_OP_READ_6:
		case SCSI_OP_WRITE_6:
		{
			scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;
			uint32 pos;
			size_t length;

			pos = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8)
				| (uint32)cmd->low_lba;
			length = cmd->length != 0 ? cmd->length : 256;

			SHOW_FLOW(3, "READ6/WRITE6 pos=%lx, length=%lx", pos, length);

			ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_6);
			return;
		}

		case SCSI_OP_READ_10:
		case SCSI_OP_WRITE_10:
		{
			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;
			uint32 pos;
			size_t length;

			pos = B_BENDIAN_TO_HOST_INT32(cmd->lba);
			length = B_BENDIAN_TO_HOST_INT16(cmd->length);

			if (length != 0) {
				ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10);
			} else {
				// we cannot transfer zero blocks (apart from LBA48)
				finish_request(qrequest, false);
			}
			return;
		}

		default:
			set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
	}

	finish_checksense(qrequest);
}
コード例 #7
0
ファイル: ata.c プロジェクト: AmirAbrams/haiku
void
ata_dpc_PIO(ide_qrequest *qrequest)
{
	ide_device_info *device = qrequest->device;
	uint32 timeout = qrequest->request->timeout > 0 ?
		qrequest->request->timeout : IDE_STD_TIMEOUT;

	SHOW_FLOW0(3, "");

	if (check_rw_error(device, qrequest)
		|| !check_rw_status(device, qrequest->is_write ? device->left_blocks > 0 : true))
	{
		// failure reported by device
		SHOW_FLOW0( 3, "command finished unsuccessfully" );

		finish_checksense(qrequest);
		return;
	}

	if (qrequest->is_write) {
		if (device->left_blocks == 0) {
			// this was the end-of-transmission IRQ
			SHOW_FLOW0(3, "write access finished");
			if (!wait_for_drqdown(device)) {
				SHOW_ERROR0(3, "device wants to transmit data though command is finished");
				goto finish;
			}
			goto finish;
		}

		// wait until device requests data
		SHOW_FLOW0(3, "Waiting for device ready to transmit");
		if (!wait_for_drq(device)) {
			SHOW_FLOW0(3, "device not ready for data transmission - abort");
			goto finish;
		}

		// start async waiting for next block/end of command
		// we should start that when block is transmitted, but with bad
		// luck the IRQ fires exactly between transmission and start of waiting,
		// so we better start waiting too early; as we are in service thread,
		// a DPC initiated by IRQ cannot overtake us, so there is no need to block
		// IRQs during sent
		start_waiting_nolock(device->bus, timeout, ide_state_async_waiting);

		// having a too short data buffer shouldn't happen here
		// anyway - we are prepared
		SHOW_FLOW0(3, "Writing one block");
		if (write_PIO_block(qrequest, 512) == B_ERROR)
			goto finish_cancel_timeout;

		--device->left_blocks;
	} else {
		if (device->left_blocks > 1) {
			// start async waiting for next command (see above)
			start_waiting_nolock(device->bus, timeout, ide_state_async_waiting);
		}

		// see write
		SHOW_FLOW0( 3, "Reading one block" );
		if (read_PIO_block(qrequest, 512) == B_ERROR)
			goto finish_cancel_timeout;

		--device->left_blocks;

		if (device->left_blocks == 0) {
			// at end of transmission, wait for data request going low
			SHOW_FLOW0( 3, "Waiting for device to finish transmission" );

			if (!wait_for_drqdown(device))
				SHOW_FLOW0( 3, "Device continues data transmission - abort command" );

			// we don't cancel timeout as no timeout is started during last block
			goto finish;
		}
	}

	return;

finish_cancel_timeout:
	cancel_irq_timeout(device->bus);

finish:
	finish_checksense(qrequest);
}