⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atapi.c

📁 newos is new operation system
💻 C
字号:
/*** Copyright 2002, Thomas Kurschel. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/bus/scsi/scsi_cmds.h>#include "ide_internal.h"#include "atapi.h"#include "ide_cmds.h"#include "ide_sim.h"#include "sync.h"#include "DMA.h"#include "PIO.h"#include "basic_prot.h"#include "queuing.h"#include "device_mgr.h"// used for MODE SENSE/SELECT 6 emulation; maximum size is 255 + header,// so this is a safe bet#define IDE_ATAPI_BUFFER_SIZE 512static bool check_packet_error( ide_device_info *device, ide_qrequest *qrequest ){	ide_bus_info *bus = device->bus;	int status;	status = bus->controller->get_altstatus( bus->channel );	if( (status & (ide_status_err | ide_status_df)) != 0 ) {		int error;		SHOW_FLOW0( 3, "packet error" );		if( bus->controller->read_command_block_regs( bus->channel,			&device->tf, ide_mask_error ) != NO_ERROR )		{			set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE );			return false;		}		error = device->tf.read.error;		if( (error & ide_error_icrc) != 0 ) {			set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_CRC );			return false;		}		if( qrequest->is_write ) {			if( (error & ide_error_wp) != 0 ) {				set_sense( device, SCSIS_KEY_DATA_PROTECT, SCSIS_ASC_WRITE_PROTECTED );				return false;			}		} else {			if( (error & ide_error_unc) != 0 ) {				set_sense( device, SCSIS_KEY_MEDIUM_ERROR, SCSIS_ASC_UNREC_READ_ERR );				return false;			}		}		if( (error & ide_error_mc) != 0 ) {			// XXX what are the additional sense data for "medium changed" ?			set_sense( device, SCSIS_KEY_UNIT_ATTENTION, SCSIS_ASC_NO_SENSE );			return false;		}		if( (error & ide_error_idnf) != 0 ) {			// XXX strange error code, don't really know what it means			set_sense( device, SCSIS_KEY_MEDIUM_ERROR, SCSIS_ASC_RANDOM_POS_ERROR );			return false;		}		if( (error & ide_error_mcr) != 0 ) {			// XXX proper sense key?			// for TUR this case is not defined !?			set_sense( device, SCSIS_KEY_UNIT_ATTENTION, SCSIS_ASC_REMOVAL_REQUESTED );			return false;		}		if( (error & ide_error_nm) != 0 ) {			set_sense( device, SCSIS_KEY_NOT_READY, SCSIS_ASC_NO_MEDIUM );			return false;		}		if( (error & ide_error_abrt) != 0 ) {			set_sense( device, SCSIS_KEY_ABORTED_COMMAND, SCSIS_ASC_NO_SENSE );			return false;		}		set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE );		return false;	}	return true;}void packet_dpc( ide_qrequest *qrequest ){	ide_device_info *device = qrequest->device;	ide_bus_info *bus = device->bus;	int status;	bigtime_t timeout = qrequest->request->cam_timeout > 0 ?		qrequest->request->cam_timeout * 1000000 : IDE_STD_TIMEOUT;	SHOW_FLOW0( 3, "" );	bus->controller->read_command_block_regs( bus->channel,		&device->tf, ide_mask_error | ide_mask_ireason );	status = bus->controller->get_altstatus( bus->channel );	if( qrequest->packet_irq ) {		qrequest->packet_irq = false;		if( !device->tf.packet_res.cmd_or_data ||			device->tf.packet_res.input_or_output ||			(status & ide_status_drq) == 0 )		{			set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_FAILURE );			goto err;		}		IDE_LOCK( bus );		if( bus->controller->write_pio_16( bus->channel,			(uint16 *)device->packet, sizeof( device->packet ) / sizeof( uint16 ),			true ) != NO_ERROR )		{			IDE_UNLOCK( bus );			goto err_int;		}		start_waiting( device->bus, timeout, ide_state_async_waiting );		return;	}	SHOW_FLOW0( 3, "2" );	if( qrequest->uses_dma ) {		bool dma_err, dev_err;		// don't check drq - if there is some data left, we cannot handle		// it anyway		// XXX does the device throw remaining data away on DMA overflow?		dma_err = finish_dma( device );		dev_err = check_packet_error( device, qrequest );		adjust_atapi_result( device, qrequest );		if( !dma_err ) {			device->DMA_failures = 0;			qrequest->request->cam_resid = 0;			finish_checksense( qrequest );		} else {			if( ++device->DMA_failures == MAX_DMA_FAILURES ) {				device->DMA_enabled = false;				finish_checksense( qrequest );			} else				finish_retry( qrequest );		}		return;	}	SHOW_FLOW0( 3, "3" );	if( (status & ide_status_drq) != 0 ) {		int length;		bool err;		SHOW_FLOW0( 3, "data transmission" );		if( device->tf.packet_res.cmd_or_data ) {			set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_FAILURE );			goto err;		}		SHOW_FLOW0( 3, "4" );		if( (device->tf.packet_res.input_or_output ^ qrequest->is_write) == 0 ) {			// XXX hm, either the device is broken or the caller has specified			// the wrong direction - what is the proper handling?			set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_FAILURE );			//xpt->block_bus( device->bus->xpt_cookie );			adjust_atapi_result( device, qrequest );			finish_checksense( qrequest );			//reset_bus( device );			//xpt->unblock_bus( device->bus->xpt_cookie );			return;		}		SHOW_FLOW0( 3, "5" );		bus->controller->read_command_block_regs( bus->channel,			&device->tf, ide_mask_byte_count );		length = device->tf.packet_res.byte_count_0_7 |			((int)device->tf.packet_res.byte_count_8_15 << 8);		SHOW_FLOW( 3, "device transmittes %i bytes\n", length );		// don't mind getting overtaken by IRQ handler - as he will		// issue a DPC for the thread context we are in, we are save		start_waiting_nolock( device->bus, timeout, ide_state_async_waiting );		if( device->tf.packet_res.input_or_output )			err = read_PIO_block( qrequest, length );		else			err = write_PIO_block( qrequest, length );		SHOW_FLOW0( 3, "6" );		// discarding data can happen but is OK		if( err == ERR_GENERAL )			goto err_int;		SHOW_FLOW0( 3, "7" );		return;	} else {		SHOW_FLOW0( 3, "no data" );		check_packet_error( device, qrequest );		adjust_atapi_result( device, qrequest );		finish_checksense( qrequest );		return;	}	return;err_int:	set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE );err:	adjust_atapi_result( device, qrequest );	finish_checksense( qrequest );}static bool create_packet_taskfile( ide_device_info *device, ide_qrequest *qrequest,	bool write ){	CCB_SCSIIO *request = qrequest->request;	int scsi_cmd = request->cam_cdb[0];	qrequest->uses_dma = device->DMA_enabled &&		(scsi_cmd == SCSI_OP_READ_6 || scsi_cmd == SCSI_OP_WRITE_6 ||		 scsi_cmd == SCSI_OP_READ_10 || scsi_cmd == SCSI_OP_WRITE_10 ||		 scsi_cmd == SCSI_OP_READ_12 || scsi_cmd == SCSI_OP_WRITE_12);	device->tf_param_mask = ide_mask_features | ide_mask_byte_count;	device->tf.packet.dma = qrequest->uses_dma;	device->tf.packet.ovl = 0;	device->tf.packet.byte_count_0_7 = request->cam_dxfer_len & 0xff;	device->tf.packet.byte_count_8_15 = request->cam_dxfer_len >> 8;	device->tf.packet.command = IDE_CMD_PACKET;	return true;}void send_packet( ide_device_info *device, ide_qrequest *qrequest, bool write ){	ide_bus_info *bus = device->bus;	bool packet_irq = device->atapi.packet_irq;	SHOW_FLOW0( 3, "" );	{		unsigned int i;		for( i = 0; i < sizeof( device->packet ); ++i )			dprintf( "%x ", device->packet[i] );	}	qrequest->is_write = write;	qrequest->packet_irq = packet_irq;	if( qrequest->uses_dma ) {		if( !prepare_dma( device, qrequest ))			qrequest->uses_dma = false;	}	SHOW_FLOW0( 3, "1" );	if( !qrequest->uses_dma )		prep_PIO_transfer( device, qrequest );	SHOW_FLOW0( 3, "2" );	if( !create_packet_taskfile( device, qrequest, write ))		goto err_setup;	SHOW_FLOW0( 3, "3" );	if( !send_command( device, !device->is_atapi,		device->atapi.packet_irq_timeout,		device->atapi.packet_irq ? ide_state_async_waiting : ide_state_accessing ))		goto err_setup;	SHOW_FLOW0( 3, "4" );	if( packet_irq )		// timeout and stuff is already set up by send_command		return;	SHOW_FLOW0( 3, "5" );	if( !ide_wait( device, ide_status_drq, ide_status_bsy, false, 100000 ))		goto err_setup;	SHOW_FLOW0( 3, "6" );	// make sure device really asks for command packet	bus->controller->read_command_block_regs( bus->channel, &device->tf,		ide_mask_ireason );	if( !device->tf.packet_res.cmd_or_data ||		device->tf.packet_res.input_or_output )	{		set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_FAILURE );		goto err_setup;	}	SHOW_FLOW0( 3, "7" );	// needed by some slow devices	cpu_spin( 10 );	if( qrequest->uses_dma ) {		// don't hurry setting up wait environment - device has to wait for DMA		if( bus->controller->write_pio_16( bus->channel,			(uint16 *)device->packet, sizeof( device->packet ) / sizeof( uint16 ),			true ) != NO_ERROR )		{			goto err_dma;		}		start_dma( device, qrequest );	} else {		bigtime_t timeout = qrequest->request->cam_timeout > 0 ?			qrequest->request->cam_timeout * 1000000 : IDE_STD_TIMEOUT;		IDE_LOCK( bus );		if( bus->controller->write_pio_16( bus->channel,			(uint16 *)device->packet, sizeof( device->packet ) / sizeof( uint16 ),			true ) != NO_ERROR )		{			goto err_pio;		}		start_waiting( bus, timeout, ide_state_async_waiting );	}	SHOW_FLOW0( 3, "8" );	return;err_pio:	IDE_UNLOCK( bus );err_dma:	set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE );err_setup:	if( qrequest->uses_dma )		abort_dma( device, qrequest );	adjust_atapi_result( device, qrequest );	finish_checksense( qrequest );}bool prep_atapi( ide_device_info *device ){	ide_device_infoblock *infoblock = &device->infoblock;	SHOW_FLOW0( 3, "" );	device->is_atapi = true;	device->exec_io = atapi_exec_io;	if( infoblock->_0.atapi.ATAPI != 2 )		return false;	switch( infoblock->_0.atapi.drq_speed ) {	case 0:	case 2:		device->atapi.packet_irq = false;		break;	case 1:		device->atapi.packet_irq = true;		device->atapi.packet_irq_timeout = IDE_STD_TIMEOUT;		break;	default:		return false;	}	SHOW_FLOW( 3, "%i", infoblock->_0.atapi.drq_speed );	/*if( infoblock->_0.atapi.packet_size != 0 )		return false;*/	device->device_type = infoblock->_0.atapi.type;	SHOW_FLOW( 3, "device_type=%i", device->device_type );	if( !initialize_qreq_array( device, 1 ) ||		!initialize_buffer( device, IDE_ATAPI_BUFFER_SIZE ) ||		!configure_DMA( device ))		return false;	return true;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -