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

📄 scsi_dsk.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/debug.h>#include <kernel/arch/cpu.h>#include <kernel/heap.h>#include <kernel/dev/blkman.h>#include <kernel/module.h>#include <kernel/bus/scsi/scsi_periph.h>#include <stdio.h>#include <stddef.h>#include <string.h>#define debug_level_flow 3#define debug_level_error 3#define debug_level_info 3#define DEBUG_MSG_PREFIX "SCSI_DSK -- "#include <kernel/debug_ext.h>#define DAS_STD_TIMEOUT 10000000#define SCSI_DSK_MODULE_NAME "dev/disk/scsi/scsi_dsk"extern blkdev_interface das_interface;blkman_interface *blkman;cam_for_driver_interface *xpt;scsi_periph_interface *scsi_periph;scsi_driver_cookie scsi_periph_cookie;typedef struct das_device_info {	scsi_device_cookie cookie;	xpt_device_cookie xpt_device;	int rw10_enabled;		// access must be atomic	blkdev_params params;	int next_tag_action;	bool removable;	char *name;	blkman_dev_cookie blkman_cookie;} das_device_info;	typedef struct das_handle_info {	scsi_handle_cookie cookie;	das_device_info *device;	int pending_error;} das_handle_info;int das_read_write( das_handle_info *handle, const phys_vecs *vecs, 	off_t pos, size_t num_blocks, size_t *bytes_transferred, bool write );	static int das_read( das_handle_info *handle, const phys_vecs *vecs, 	off_t pos, size_t num_blocks, size_t *bytes_transferred ){	return das_read_write( handle, vecs, pos, 		num_blocks, bytes_transferred, false );}	static int das_write( das_handle_info *handle, const phys_vecs *vecs, 	off_t pos, size_t num_blocks, size_t *bytes_transferred ){	return das_read_write( handle, vecs, pos, 		num_blocks, bytes_transferred, true );}int das_read_write( das_handle_info *handle, const phys_vecs *vecs, 	off_t pos, size_t num_blocks, size_t *bytes_transferred, bool write ){	das_device_info *device = handle->device;	CCB_SCSIIO *request;	err_res res;	int retries = 0;	int err;		if( num_blocks >= 0x10000 ) {		num_blocks = 0x10000;	}		if( pos >= 0x100000000 )		return ERR_INVALID_ARGS;	request = (CCB_SCSIIO *)xpt->ccb_alloc( device->xpt_device );		if( request == NULL )		return ERR_NO_MEMORY;	do {		CCB_HEADER *ccb;		int num_bytes;				ccb = &request->cam_ch;				ccb->cam_func_code = XPT_SCSI_IO;		//ccb->cam_path_id = device->path_id;		//ccb->cam_target_id = device->target_id;		//ccb->cam_target_lun = device->target_lun;		ccb->cam_flags = write ? CAM_DIR_OUT : CAM_DIR_IN;				if( !device->rw10_enabled && num_blocks > 0x100 )			num_blocks = 0x100;					num_bytes = num_blocks * device->params.block_size;				request->cam_data = NULL;		request->cam_sg_list = (struct sg_elem *)vecs->vec;		request->cam_dxfer_len = num_bytes;		request->cam_sglist_cnt = vecs->num;		request->cam_sort = pos;		request->cam_timeout = DAS_STD_TIMEOUT;		request->cam_tag_action = atomic_set( &device->next_tag_action, 			CAM_SIMPLE_QTAG );				if( pos + num_blocks < 0x200000 && num_blocks <= 0x100 ) {			scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cam_cdb;						memset( cmd, 0, sizeof( *cmd ));			cmd->opcode = write ? 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 = num_blocks;						request->cam_cdb_len = sizeof( *cmd );		} else {			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cam_cdb;						if( !device->rw10_enabled ) {				err = ERR_INVALID_ARGS;				goto abort;			}						memset( cmd, 0, sizeof( *cmd ));			cmd->opcode = write ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10;			cmd->RelAdr = 0;			cmd->FUA = 0;			cmd->DPO = 0;						cmd->top_LBA = (pos >> 24) & 0xff;			cmd->high_LBA = (pos >> 16) & 0xff;			cmd->mid_LBA = (pos >> 8) & 0xff;			cmd->low_LBA = pos & 0xff;						cmd->high_length = (num_blocks >> 8) & 0xff;			cmd->low_length = num_blocks & 0xff;						request->cam_cdb_len = sizeof( *cmd );		}				err = handle->pending_error;				if( err ) 			goto abort;					xpt->action( &request->cam_ch );				sem_acquire( request->cam_ch.completion_sem, 1 );			res = scsi_periph->check_error( device->cookie, request );					switch( res.action ) {		case err_act_ok:			*bytes_transferred = num_bytes - request->cam_resid;			break;					case err_act_start:			res = scsi_periph->send_start_stop( 				device->cookie, request, 1, device->removable );			if( res.action == err_act_ok )				res.action = err_act_retry;			break;					case err_act_invalid_req:			if( device->rw10_enabled ) {				device->rw10_enabled = false;				res.action = err_act_retry;			} else				res.action = err_act_fail;			break;		}			} while( res.action == err_act_retry && retries++ < 3 );		xpt->ccb_free( (CCB_HEADER *)request );		if( res.error_code == ERR_DEV_READ_ERROR && write )		return ERR_DEV_WRITE_ERROR;	else		return res.error_code;			abort:	xpt->ccb_free( (CCB_HEADER *)request );			return err;}// unused#if 0static int log2( uint32 x ){	int y;		for( y = 31; y >= 0; --y )		if( x == ((uint32)1 << y) )			break;				return y;}#endifstatic int das_ioctl( das_handle_info *handle, int op, void *buf, size_t len ){	switch( op ) {	case IOCTL_GET_MEDIA_STATUS:		return scsi_periph->get_media_status( handle->cookie );			default:		return ERR_INVALID_ARGS;	}}static int das_device_init( periph_cookie periph, scsi_device_cookie cookie,	scsi_res_inquiry *device_inquiry, CAM_SIM_PARAMS *sim_inquiry, 	xpt_device_cookie xpt_device, CCB_HEADER *ccb, das_device_info **device_out ){	das_device_info *device;	int res;		SHOW_FLOW0( 3, "" );		device = kmalloc( sizeof( *device ));	if( device == NULL )		return ERR_NO_MEMORY;	memset( device, 0, sizeof( *device ));	device->cookie = cookie;			device->xpt_device = xpt_device;	device->removable = device_inquiry->RMB;		device->next_tag_action = CAM_SIMPLE_QTAG;	device->rw10_enabled = true;	memset( &device->params, 0, sizeof( device->params ));	device->params.alignment = sim_inquiry->dma_alignment;	device->params.max_sg_num = max( sim_inquiry->max_sg_num, 1 );	device->params.max_blocks = min( sim_inquiry->max_blocks, 0x10000 );		device->name = scsi_periph->compose_device_name( device->cookie, "disk/scsi" );	if( device->name == NULL ) {		res = ERR_NO_MEMORY;		goto err;	}		SHOW_FLOW( 3, "name=%s", device->name );		device->params.alignment = sim_inquiry->dma_alignment;	device->params.max_blocks = sim_inquiry->max_blocks;	device->params.dma_boundary = sim_inquiry->dma_boundary;	device->params.dma_boundary_solid = sim_inquiry->dma_boundary_solid;	device->params.max_sg_num = sim_inquiry->max_sg_num;	// return device pointer before using scsi_periph calls	*device_out = device;		SHOW_FLOW0( 3, "2" );	scsi_periph->check_capacity( device->cookie, ccb );		SHOW_FLOW0( 3, "3" );	res = blkman->register_blkdev( &das_interface, (blkdev_cookie)device,		device->name, &device->blkman_cookie, &device->params );	if( res != NO_ERROR )		goto err2;	SHOW_FLOW0( 3, "done" );	return NO_ERROR;	err2:		kfree( device->name );err:	kfree( device );	return res;}static bool das_is_supported( periph_cookie periph, CCB_GETDEV *dev_type ){			return dev_type->cam_pd_type == scsi_dev_direct_access;}static int das_device_removed( das_device_info *device ){	blkman->unregister_blkdev( device->blkman_cookie );	return NO_ERROR;}static void das_handle_set_error( das_handle_info *handle, int error_code ){	handle->pending_error = error_code;}static int das_handle_get_error( das_handle_info *handle ){	return handle->pending_error;}static void das_async( periph_cookie periph, 	int path_id, int target_id, int lun, 	int code, const void *data, int data_len ){}static int das_device_uninit( das_device_info *device ){	kfree( device->name );	kfree( device );	return NO_ERROR;}static void das_set_capacity( das_device_info *device, uint64 capacity,	uint32 block_size ){	SHOW_FLOW( 3, "device=%p", device );		device->params.capacity = capacity;	device->params.block_size = block_size;		// during init, capacity is checked before device is registered	// at blkman, thus we need this test	if( device->blkman_cookie != NULL )		blkman->set_capacity( device->blkman_cookie, capacity, block_size );}scsi_periph_callbacks callbacks = {	(bool (*)( periph_cookie, CCB_GETDEV * ))		das_is_supported,	(int (*)( periph_cookie, scsi_device_cookie,		scsi_res_inquiry *, CAM_SIM_PARAMS *, 		xpt_device_cookie, CCB_HEADER *, 		periph_device_cookie * ))					das_device_init,	(int (*)( periph_device_cookie ))				das_device_removed,	(int (*)( periph_device_cookie periph_device ))	das_device_uninit,	(void (*)( periph_handle_cookie, int ))			das_handle_set_error,	(int (*)( periph_handle_cookie ))				das_handle_get_error,	(void (*)( periph_device_cookie, 		uint64, uint32 ))							das_set_capacity,		(void (*)( periph_cookie, 		int, int, int, int, const void *, int ))	das_async};static int das_open( das_device_info *device, das_handle_info **handle_out ){	das_handle_info *handle;	int res;		handle = kmalloc( sizeof( *handle ));	if( handle == NULL )		return ERR_NO_MEMORY;			handle->device = device;			res = scsi_periph->handle_open( device->cookie, (periph_handle_cookie)handle, 		&handle->cookie );	if( res != NO_ERROR ) {		kfree( handle );		return res;	}	*handle_out = handle;		return NO_ERROR;}static int das_close( das_handle_info *handle ){	scsi_periph->handle_close( handle->cookie );	kfree( handle );		return NO_ERROR;}blkdev_interface das_interface = {	(int (*)( blkdev_cookie, blkdev_handle_cookie * ))			&das_open,	(int (*)( blkdev_handle_cookie ))							&das_close,		(int (*)( blkdev_handle_cookie, const phys_vecs *, 		off_t, size_t, size_t * ))								&das_read,	(int (*)( blkdev_handle_cookie, const phys_vecs *,		off_t, size_t, size_t * ))								&das_write,	(int (*)( blkdev_handle_cookie, int, void *, size_t ))		&das_ioctl,};static int das_init( void ){	int res;	SHOW_FLOW0( 3, "" );			res = module_get( CAM_FOR_DRIVER_MODULE_NAME, 0, (void **)&xpt );	if( res != NO_ERROR )		return res;	SHOW_FLOW0( 3, "1" );			res = module_get( BLKMAN_MODULE_NAME, 0, (void **)&blkman );	if( res != NO_ERROR )		goto err1;		SHOW_FLOW0( 3, "2" );			res = module_get( SCSI_PERIPH_MODULE_NAME, 0, (void **)&scsi_periph );	if( res != NO_ERROR )		goto err2;			SHOW_FLOW0( 3, "3" );			res = scsi_periph->register_driver( &callbacks, 		NULL, &scsi_periph_cookie );	if( res != NO_ERROR )		goto err3;			SHOW_FLOW0( 3, "4" );			return NO_ERROR;	err3:	module_put( SCSI_PERIPH_MODULE_NAME );err2:	module_put( BLKMAN_MODULE_NAME );err1:	module_put( CAM_FOR_DRIVER_MODULE_NAME );	return res;}static int das_uninit( void ){	int res;		SHOW_FLOW0( 3, "" );	res = scsi_periph->unregister_driver( scsi_periph_cookie );	if( res != NO_ERROR )		return res;		module_put( SCSI_PERIPH_MODULE_NAME );	module_put( BLKMAN_MODULE_NAME );	module_put( CAM_FOR_DRIVER_MODULE_NAME );		return NO_ERROR;}// dummy to make module manager happyvoid *das_module_interface = NULL;module_header scsi_dsk_module = {	SCSI_DSK_MODULE_NAME,	MODULE_CURR_VERSION,	0,		&das_module_interface,		das_init,	das_uninit};module_header *modules[] ={	&scsi_dsk_module,	NULL};

⌨️ 快捷键说明

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