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

📄 scsi2ata.c

📁 newos is new operation system
💻 C
字号:
/* ** Copyright 2002, Thomas Kurschel. All rights reserved.** Distributed under the terms of the NewOS License.*/#include "ide_internal.h"#include "ata.h"#include <string.h>#include "ide_sim.h"#include "ide_cmds.h"#include "basic_prot.h"static void mode_sense_6( ide_device_info *device, ide_qrequest *qrequest ){	CCB_SCSIIO *request = qrequest->request;	scsi_cmd_mode_sense_6 *cmd = (scsi_cmd_mode_sense_6 *)request->cam_cdb;	scsi_mode_param_header_6 *param_header;	scsi_modepage_contr *contr;	scsi_mode_param_block_desc *block_desc;	size_t total_length = 		sizeof( scsi_mode_param_header_6 ) +		sizeof( scsi_mode_param_block_desc ) +		sizeof( scsi_modepage_contr );	scsi_mode_param_dev_spec_da devspec = {		res0_0 : 0,		DPOFUA : 0,		res0_6 : 0,		WP : 0	};		// 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->PC != SCSI_MODE_SENE_PC_CURRENT &&		 cmd->PC != SCSI_MODE_SENE_PC_SAVED) ||		cmd->allocation_length < total_length ||		request->cam_dxfer_len < total_length ) 	{		request->cam_ch.cam_status = CAM_REQ_INVALID;		finish_request( qrequest );		return;	}	param_header = (scsi_mode_param_header_6 *)request->cam_data;	param_header->mode_data_len = total_length - 1;	param_header->medium_type = 0; 		// XXX standard is a bit vague here	param_header->dev_spec_parameter = *(uint8 *)&devspec;	param_header->block_desc_len = sizeof( scsi_mode_param_block_desc );		block_desc = (scsi_mode_param_block_desc *)(request->cam_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;	contr = (scsi_modepage_contr *)(request->cam_data 		+ sizeof( *param_header )		+ param_header->block_desc_len );		memset( contr, 0, sizeof( *contr ));	contr->RLEC = false;	contr->DQue = !device->CQ_enabled;	contr->QErr = false;				// when a command fails we requeue all 										// lost commands automagically	contr->QAM = SCSI_QAM_UNRESTRICTED;	request->cam_ch.cam_status = CAM_REQ_CMP;	finish_request( qrequest );	return;}static void ata_request_sense( ide_device_info *device, ide_qrequest *qrequest ){	CCB_SCSIIO *request = qrequest->request;	scsi_cmd_request_sense *cmd = (scsi_cmd_request_sense *)request->cam_cdb;	scsi_sense sense;	int data_len;		// 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		data_len = min( request->cam_dxfer_len, cmd->alloc_length );	data_len = min( data_len, (int)sizeof( sense ));	if( device->combined_sense ) {		create_sense( device, &sense );		memcpy( request->cam_data, &sense, data_len );	} else		memset( request->cam_data, 0, data_len );	request->cam_resid = request->cam_dxfer_len - data_len;	request->cam_dxfer_len = data_len;		device->combined_sense = 0;		request->cam_ch.cam_status = CAM_REQ_CMP;	finish_request( qrequest );}static bool mode_select_contrpage( ide_device_info *device, ide_qrequest *qrequest,	scsi_modepage_contr *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;	}	enable_CQ( device, !page->DQue );	return true;}static void mode_select_6( ide_device_info *device, ide_qrequest *qrequest ){	CCB_SCSIIO *request = qrequest->request;	scsi_cmd_mode_select_6 *cmd = (scsi_cmd_mode_select_6 *)request->cam_cdb;	scsi_mode_param_header_6 *param_header;	scsi_modepage_header *page_header;	int total_length;	int left_length;		if( cmd->SP || cmd->PF != 1 ) {		set_sense( device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD );		return;	}		total_length = min( request->cam_dxfer_len, cmd->param_list_length );		if( total_length < (int)sizeof( scsi_mode_param_header_6 )) {		set_sense( device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR );		return;	}		param_header = (scsi_mode_param_header_6 *)request->cam_data;	total_length = min( total_length, param_header->mode_data_len + 1 );		left_length = total_length - param_header->block_desc_len - 		sizeof( *param_header );			page_header = (scsi_modepage_header *)(request->cam_data + 		sizeof( *param_header ) + param_header->block_desc_len );			while( left_length > 0 ) {		int page_len;				if( left_length < (int)sizeof( scsi_modepage_header )) {			set_sense( device, 				SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR );			return;		}					page_len = page_header->page_length + sizeof( scsi_modepage_header );		if( left_length < page_len ) {			set_sense( device, 				SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR );			return;		}		switch( page_header->page_code ) {		case SCSI_MODEPAGE_CONTROL:			if( !mode_select_contrpage( device, qrequest,				(scsi_modepage_contr *)page_header ))				return;			break;					default:			set_sense( device, 				SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_PARAM_LIST_FIELD );			return;		}				page_header = (scsi_modepage_header *)(((char *)page_header) + page_len);		left_length -= page_len;	}	// plain paranoia, we shouldn't arrive here	set_sense( device, 		SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR );}static bool ata_tur( ide_device_info *device, ide_qrequest *qrequest ){	SHOW_FLOW0( 3, "" );		if( !device->infoblock.RMSN_supported ||		device->infoblock._127_RMSN_support != 1 )		return true;			// 5322	device->tf_param_mask = 0;	device->tf.write.command = IDE_CMD_GET_MEDIA_STATUS;		if( !send_command( device, true, 15000000, ide_state_sync_waiting )) 		return false;	// bits ide_error_mcr | ide_error_mc | ide_error_wp are also valid	// but not requested by TUR	return check_output( device, true, ide_error_nm | ide_error_abrt, false );}static bool ata_flush_cache( ide_device_info *device, ide_qrequest *qrequest ){	ide_bus_info *bus = device->bus;		// we should ask for FLUSH CACHE support, but everyone denies it	// (looks like they cheat to gain some performance advantage, but	//  that's pretty useless: everyone does it...)	if( !device->infoblock.write_cache_supported )		return true;		device->tf_param_mask = 0;	device->tf.lba.command = device->use_48bits ? IDE_CMD_FLUSH_CACHE_EXT 		: IDE_CMD_FLUSH_CACHE;		// spec says that this may take more then 30s, how much more?	if( !send_command( device, true, 60000000, ide_state_sync_waiting ))		return false;		sem_acquire( bus->sync_wait_sem, 1 );	return check_output( device, true, ide_error_abrt, false );}static bool ata_load_eject( ide_device_info *device, ide_qrequest *qrequest, bool load ){	if( load ) {		set_sense( device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_NOT_SUPPORTED );		return false;	}		device->tf_param_mask = 0;	device->tf.lba.command = IDE_CMD_MEDIA_EJECT;		if( !send_command( device, true, 15000000, ide_state_sync_waiting ))		return false;			sem_acquire( device->bus->sync_wait_sem, 1 );		return check_output( device, true, ide_error_abrt | ide_error_nm, false );}static bool ata_prevent_allow( ide_device_info *device, bool prevent ){	set_sense( device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_ILL_FUNCTION );	return false;}static void ata_inquiry( ide_device_info *device, ide_qrequest *qrequest ){	CCB_SCSIIO *request = qrequest->request;	scsi_res_inquiry *data = (scsi_res_inquiry *)request->cam_data;	scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cam_cdb;		SHOW_FLOW0( 3, "" );		if( cmd->EVPD || cmd->page_code ) {		set_sense( device, 			SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD );		return;	}		SHOW_FLOW0( 3, "1" );		if( request->cam_dxfer_len < 36 ) {		// we could return truncated data, but it's probably		// not worth the hazzle		request->cam_ch.cam_status = CAM_REQ_INVALID;		return;	}		SHOW_FLOW0( 3, "2" );						memset( request->cam_data, 0, request->cam_dxfer_len );		data->device_type = scsi_dev_direct_access;	data->device_qualifier = scsi_periph_qual_connected;		data->device_type_modifier = 0;	data->RMB = false;		data->ANSI_version = 2;	data->ECMA_version = 0;	data->ISO_version = 0;		data->response_data_format = 2;	data->TrmIOP = false;		// to be changed if we support TERM I/O	data->additional_length = sizeof( scsi_res_inquiry ) - 4;		data->SftRe = false;	data->CmdQue = device->CQ_supported;	data->Linked = false;		// these values are free-style	data->Sync = false;	data->WBus16 = true;	data->WBus32 = false;		data->RelAdr = false;		// the following fields are *much* to small, sigh...	memcpy( data->vendor_ident, device->infoblock.model_number, 8 );	memcpy( data->product_ident, device->infoblock.model_number + 8, 16 );	memcpy( data->product_rev, "    ", 4 );		request->cam_resid = request->cam_dxfer_len - sizeof( scsi_res_inquiry );}static void read_capacity( ide_device_info *device, ide_qrequest *qrequest ){	CCB_SCSIIO *request = qrequest->request;	scsi_res_read_capacity *data = (scsi_res_read_capacity *)request->cam_data;	scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cam_cdb;			if( request->cam_dxfer_len < 4 ) {		// there is no point supporting short data		request->cam_ch.cam_status = CAM_REQ_INVALID;		return;	}			if( cmd->PMI || cmd->top_LBA || cmd->high_LBA || cmd->mid_LBA || cmd->low_LBA ) 	{		set_sense( device, 			SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD );		return;	}			data->top_block_size = (512 >> 24) & 0xff;	data->high_block_size = (512 >> 16) & 0xff;	data->mid_block_size = (512 >> 8) & 0xff;	data->low_block_size = 512 & 0xff;		data->top_LBA = (device->total_sectors >> 24) & 0xff;	data->high_LBA = (device->total_sectors >> 16) & 0xff;	data->mid_LBA = (device->total_sectors >> 8) & 0xff;	data->low_LBA = device->total_sectors & 0xff;		request->cam_resid = request->cam_dxfer_len - sizeof( *data );}void ata_exec_io( ide_device_info *device, ide_qrequest *qrequest ){	CCB_SCSIIO *request = qrequest->request;		SHOW_FLOW( 3, "command=%x", request->cam_cdb[0] );	if( request->cam_cdb[0] != SCSI_OP_REQUEST_SENSE )			start_request( device, qrequest );		switch( request->cam_cdb[0] ) {	case SCSI_OP_TUR:		ata_tur( device, qrequest );		break;	case SCSI_OP_REQUEST_SENSE:		ata_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		// (exception are removable media devices, but to my knowledge		// they don't have to be formatted as well)		request->cam_ch.cam_status = CAM_REQ_INVALID;		break;;	case SCSI_OP_INQUIRY: 		ata_inquiry( device, qrequest );		break;;	case SCSI_OP_MODE_SELECT_6:		mode_select_6( device, qrequest );		break;;				case SCSI_OP_MODE_SENSE_6:		mode_sense_6( device, qrequest );		break;;		case SCSI_OP_MODE_SELECT_10:	case SCSI_OP_MODE_SENSE_10:		/// XXX to do		request->cam_ch.cam_status = CAM_REQ_INVALID;		break;			case SCSI_OP_RESERVE:	case SCSI_OP_RELEASE:		// though mandatory, this doesn't make much sense in a		// single initiator environment		request->cam_ch.cam_status = CAM_REQ_INVALID;		break;			case SCSI_OP_START_STOP: {		scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cam_cdb;		//ide_qrequest *qrequest = get_request_priv( request )->qrequest;				// with no LoEj bit set, we should only allow/deny further access		// we ignore that		// with LoEj bit set, we should additionally either load or eject the medium		// (start = 0 - eject; start = 1 - load)				if( !cmd->start )			// we must flush cache if start = 0			ata_flush_cache( device, qrequest );				if( cmd->LoEj )			ata_load_eject( device, qrequest, cmd->start );					break; }			case SCSI_OP_PREVENT_ALLOW: {		scsi_cmd_prevent_allow *cmd = (scsi_cmd_prevent_allow *)request->cam_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?		// it effectly does a read-and-compare, which IDE doesn't support		request->cam_ch.cam_status = CAM_REQ_INVALID;		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->cam_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;				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->cam_cdb;		uint32 pos;		size_t length;				pos = ((uint32)cmd->top_LBA << 24) | ((uint32)cmd->high_LBA << 16) 			| ((uint32)cmd->mid_LBA << 8) | (uint32)cmd->low_LBA;					length = ((uint32)cmd->high_length << 8) | cmd->low_length;				if( length != 0 ) {			ata_send_rw( device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10 );		} else {			// we cannot transfer zero bytes (apart from LBA48)			finish_request( qrequest );		}		return;	}	default:		set_sense( device, 			SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE );	}		finish_checksense( qrequest );}

⌨️ 快捷键说明

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