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

📄 ftape-ctl.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	 */	switch (qic_std) {	case QIC_TAPE_QIC40:		speed = (data_rate == 250) ? 250 : 500;		break;	case QIC_TAPE_QIC80:		speed = (data_rate == 500) ? 340 : 680;		break;	case QIC_TAPE_QIC3010:		speed = (data_rate == 500) ? 226 : 452;		break;	case QIC_TAPE_QIC3020:		speed = (data_rate == 1000) ? 226 : 452;		break;	default:		TRACE(ft_t_bug, "Unknown qic_std (bug) ?");		speed = 500;		break;	}	if (ft_drive_type.speed == 0) {		unsigned long t0;		static int dt = 0;     /* keep gcc from complaining */		static int first_time = 1;		/*  Measure the time it takes to wind to EOT and back to BOT.		 *  If the tape length is known, calculate the rewind speed.		 *  Else keep the time value for calculation of the rewind		 *  speed later on, when the length _is_ known.		 *  Ask for a report only when length and speed are both known.		 */		if (first_time) {			ftape_seek_to_bot();			t0 = jiffies;			ftape_seek_to_eot();			ftape_seek_to_bot();			dt = (int) (((jiffies - t0) * FT_USPT) / 1000);			if (dt < 1) {				dt = 1;	/* prevent div by zero on failures */			}			first_time = 0;			TRACE(ft_t_info,			      "trying to determine seek timeout, got %d msec",			      dt);		}		if (tape_len != 0) {			ft_drive_type.speed = 				(2 * 12 * tape_len * 1000) / dt;			TRACE(ft_t_warn, "\n"		     KERN_INFO "==========================================\n"		     KERN_INFO "drive type: %s\n"		     KERN_INFO "delta time = %d ms, length = %d ft\n"		     KERN_INFO "has a maximum tape speed of %d ips\n"		     KERN_INFO "please report this to "THE_FTAPE_MAINTAINER"\n"		     KERN_INFO "==========================================",			      ft_drive_type.name, dt, tape_len, 			      ft_drive_type.speed);		}	}	/*  Handle unknown length tapes as very long ones. We'll	 *  determine the actual length from a header segment later.	 *  This is normal for all modern (Wide,TR1/2/3) formats.	 */	if (tape_len <= 0) {		TRACE(ft_t_noise,		      "Unknown tape length, using maximal timeouts");		length = QIC_TOP_TAPE_LEN;	/* use worst case values */	} else {		length = tape_len;		/* use actual values */	}	if (ft_drive_type.speed == 0) {		ff_speed = speed; 	} else {		ff_speed = ft_drive_type.speed;	}	/*  time to go from bot to eot at normal speed (data rate):	 *  time = (1+delta) * length (ft) * 12 (inch/ft) / speed (ips)	 *  delta = 10 % for seek speed, 20 % for rewind speed.	 */	ftape_timeout.seek = (length * 132 * FT_SECOND) / speed;	ftape_timeout.rewind = (length * 144 * FT_SECOND) / (10 * ff_speed);	ftape_timeout.reset = 20 * FT_SECOND + ftape_timeout.rewind;	TRACE(ft_t_noise, "timeouts for speed = %d, length = %d\n"	      KERN_INFO "seek timeout  : %d sec\n"	      KERN_INFO "rewind timeout: %d sec\n"	      KERN_INFO "reset timeout : %d sec",	      speed, length,	      (ftape_timeout.seek + 500) / 1000,	      (ftape_timeout.rewind + 500) / 1000,	      (ftape_timeout.reset + 500) / 1000);	TRACE_EXIT;}/* This function calibrates the datarate (i.e. determines the maximal * usable data rate) and sets the global variable ft_qic_std to qic_std * */int ftape_calibrate_data_rate(unsigned int qic_std){	int rate = ft_fdc_rate_limit;	int result;	TRACE_FUN(ft_t_flow);	ft_qic_std = qic_std;	if (ft_qic_std == -1) {		TRACE_ABORT(-EIO, ft_t_err,		"Unable to determine data rate if QIC standard is unknown");	}	/*  Select highest rate supported by both fdc and drive.	 *  Start with highest rate supported by the fdc.	 */	while (fdc_set_data_rate(rate) < 0 && rate > 250) {		rate /= 2;	}	TRACE(ft_t_info,	      "Highest FDC supported data rate: %d Kbps", rate);	ft_fdc_max_rate = rate;	do {		result = ftape_set_data_rate(rate, ft_qic_std);	} while (result == -EINVAL && (rate /= 2) > 250);	if (result < 0) {		TRACE_ABORT(-EIO, ft_t_err, "set datarate failed");	}	ft_data_rate = rate;	TRACE_EXIT 0;}static int ftape_init_drive(void){	int status;	qic_model model;	unsigned int qic_std;	unsigned int data_rate;	TRACE_FUN(ft_t_flow);	ftape_init_drive_needed = 0; /* don't retry if this fails ? */	TRACE_CATCH(ftape_report_raw_drive_status(&status),);	if (status & QIC_STATUS_CARTRIDGE_PRESENT) {		if (!(status & QIC_STATUS_AT_BOT)) {			/*  Antique drives will get here after a soft reset,			 *  modern ones only if the driver is loaded when the			 *  tape wasn't rewound properly.			 */			/* Tape should be at bot if new cartridge ! */			ftape_seek_to_bot();		}		if (!(status & QIC_STATUS_REFERENCED)) {			TRACE(ft_t_flow, "starting seek_load_point");			TRACE_CATCH(ftape_command_wait(QIC_SEEK_LOAD_POINT,						       ftape_timeout.reset,						       &status),);		}	}	ft_formatted = (status & QIC_STATUS_REFERENCED) != 0;	if (!ft_formatted) {		TRACE(ft_t_warn, "Warning: tape is not formatted !");	}	/*  report configuration aborts when ftape_tape_len == -1	 *  unknown qic_std is okay if not formatted.	 */	TRACE_CATCH(ftape_report_configuration(&model,					       &data_rate,					       &qic_std,					       &ftape_tape_len),);	/*  Maybe add the following to the /proc entry	 */	TRACE(ft_t_info, "%s drive @ %d Kbps",	      (model == prehistoric) ? "prehistoric" :	      ((model == pre_qic117c) ? "pre QIC-117C" :	       ((model == post_qic117b) ? "post QIC-117B" :		"post QIC-117D")), data_rate);	if (ft_formatted) {		/*  initialize ft_used_data_rate to maximum value 		 *  and set ft_qic_std		 */		TRACE_CATCH(ftape_calibrate_data_rate(qic_std),);		if (ftape_tape_len == 0) {			TRACE(ft_t_info, "unknown length QIC-%s tape",			      (ft_qic_std == QIC_TAPE_QIC40) ? "40" :			      ((ft_qic_std == QIC_TAPE_QIC80) ? "80" :			       ((ft_qic_std == QIC_TAPE_QIC3010) 				? "3010" : "3020")));		} else {			TRACE(ft_t_info, "%d ft. QIC-%s tape", ftape_tape_len,			      (ft_qic_std == QIC_TAPE_QIC40) ? "40" :			      ((ft_qic_std == QIC_TAPE_QIC80) ? "80" :			       ((ft_qic_std == QIC_TAPE_QIC3010)				? "3010" : "3020")));		}		ftape_calc_timeouts(ft_qic_std, ft_data_rate, ftape_tape_len);		/* soft write-protect QIC-40/QIC-80 cartridges used with a		 * Colorado T3000 drive. Buggy hardware!		 */		if ((ft_drive_type.vendor_id == 0x011c6) &&		    ((ft_qic_std == QIC_TAPE_QIC40 ||		      ft_qic_std == QIC_TAPE_QIC80) &&		     !ft_write_protected)) {			TRACE(ft_t_warn, "\n"	KERN_INFO "The famous Colorado T3000 bug:\n"	KERN_INFO "%s drives can't write QIC40 and QIC80\n"	KERN_INFO "cartridges but don't set the write-protect flag!",			      ft_drive_type.name);			ft_write_protected = 1;		}	} else {		/*  Doesn't make too much sense to set the data rate		 *  because we don't know what to use for the write		 *  precompensation.		 *  Need to do this again when formatting the cartridge.		 */		ft_data_rate = data_rate;		ftape_calc_timeouts(QIC_TAPE_QIC40,				    data_rate,				    ftape_tape_len);	}	ftape_new_cartridge();	TRACE_EXIT 0;}static void ftape_munmap(void){	int i;	TRACE_FUN(ft_t_flow);		for (i = 0; i < ft_nr_buffers; i++) {		ft_buffer[i]->mmapped = 0;	}	TRACE_EXIT;}/*   Map the dma buffers into the virtual address range given by vma. *   We only check the caller doesn't map non-existent buffers. We *   don't check for multiple mappings. */int ftape_mmap(struct vm_area_struct *vma){	int num_buffers;	int i;	TRACE_FUN(ft_t_flow);		if (ft_failure) {		TRACE_EXIT -ENODEV;	}	if (!(vma->vm_flags & (VM_READ|VM_WRITE))) {		TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access");	}	if (vma_get_pgoff(vma) != 0) {		TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0");	}	if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) {		TRACE_ABORT(-EINVAL, ft_t_err,			    "size = %ld, should be a multiple of %d",			    vma->vm_end - vma->vm_start,			    FT_BUFF_SIZE);	}	num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE;	if (num_buffers > ft_nr_buffers) {		TRACE_ABORT(-EINVAL,			    ft_t_err, "size = %ld, should be less than %d",			    vma->vm_end - vma->vm_start,			    ft_nr_buffers * FT_BUFF_SIZE);	}	if (ft_driver_state != idle) {		/* this also clears the buffer states 		 */		ftape_abort_operation();	} else {		ftape_reset_buffer();	}	for (i = 0; i < num_buffers; i++) {		unsigned long pfn;		pfn = virt_to_phys(ft_buffer[i]->address) >> PAGE_SHIFT;		TRACE_CATCH(remap_pfn_range(vma, vma->vm_start +					     i * FT_BUFF_SIZE,					     pfn,					     FT_BUFF_SIZE,					     vma->vm_page_prot),			    _res = -EAGAIN);		TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p",		      ft_buffer[i]->address,		      (void *)(vma->vm_start + i * FT_BUFF_SIZE));	}	for (i = 0; i < num_buffers; i++) {		memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE);		ft_buffer[i]->mmapped++;	}		TRACE_EXIT 0;}static void ftape_init_driver(void); /* forward declaration *//*      OPEN routine called by kernel-interface code */int ftape_enable(int drive_selection){	TRACE_FUN(ft_t_any);	if (ft_drive_sel == -1 || ft_drive_sel != drive_selection) {		/* Other selection than last time		 */		ftape_init_driver();	}	ft_drive_sel = FTAPE_SEL(drive_selection);	ft_failure = 0;	TRACE_CATCH(fdc_init(),); /* init & detect fdc */	TRACE_CATCH(ftape_activate_drive(&ft_drive_type),		    fdc_disable();		    fdc_release_irq_and_dma();		    fdc_release_regions());	TRACE_CATCH(ftape_get_drive_status(), ftape_detach_drive());	if (ft_drive_type.vendor_id == UNKNOWN_VENDOR) {		ftape_log_vendor_id();	}	if (ft_new_tape) {		ftape_init_drive_needed = 1;	}	if (!ft_no_tape && ftape_init_drive_needed) {		TRACE_CATCH(ftape_init_drive(), ftape_detach_drive());	}	ftape_munmap(); /* clear the mmap flag */	clear_history();	TRACE_EXIT 0;}/*   release routine called by the high level interface modules *   zftape or sftape. */void ftape_disable(void){	int i;	TRACE_FUN(ft_t_any);	for (i = 0; i < ft_nr_buffers; i++) {		if (ft_buffer[i]->mmapped) {			TRACE(ft_t_noise, "first byte of buffer %d: 0x%02x",			      i, *ft_buffer[i]->address);		}	}	if (sigtestsetmask(&current->pending.signal, _DONT_BLOCK) && 	    !(sigtestsetmask(&current->pending.signal, _NEVER_BLOCK)) &&	    ftape_tape_running) {		TRACE(ft_t_warn,		      "Interrupted by fatal signal and tape still running");		ftape_dumb_stop();		ftape_abort_operation(); /* it's annoying */	} else {		ftape_set_state(idle);	}	ftape_detach_drive();	if (ft_history.used) {		TRACE(ft_t_info, "== Non-fatal errors this run: ==");		TRACE(ft_t_info, "fdc isr statistics:\n"		      KERN_INFO " id_am_errors     : %3d\n"		      KERN_INFO " id_crc_errors    : %3d\n"		      KERN_INFO " data_am_errors   : %3d\n"		      KERN_INFO " data_crc_errors  : %3d\n"		      KERN_INFO " overrun_errors   : %3d\n"		      KERN_INFO " no_data_errors   : %3d\n"		      KERN_INFO " retries          : %3d",		      ft_history.id_am_errors,   ft_history.id_crc_errors,		      ft_history.data_am_errors, ft_history.data_crc_errors,		      ft_history.overrun_errors, ft_history.no_data_errors,		      ft_history.retries);		if (ft_history.used & 1) {			TRACE(ft_t_info, "ecc statistics:\n"			      KERN_INFO " crc_errors       : %3d\n"			      KERN_INFO " crc_failures     : %3d\n"			      KERN_INFO " ecc_failures     : %3d\n"			      KERN_INFO " sectors corrected: %3d",			      ft_history.crc_errors,   ft_history.crc_failures,			      ft_history.ecc_failures, ft_history.corrected);		}		if (ft_history.defects > 0) {			TRACE(ft_t_warn, "Warning: %d media defects!",			      ft_history.defects);		}		if (ft_history.rewinds > 0) {			TRACE(ft_t_info, "tape motion statistics:\n"			      KERN_INFO "repositions       : %3d",			      ft_history.rewinds);		}	}	ft_failure = 1;	TRACE_EXIT;}static void ftape_init_driver(void){	TRACE_FUN(ft_t_flow);	ft_drive_type.vendor_id = UNKNOWN_VENDOR;	ft_drive_type.speed     = 0;	ft_drive_type.wake_up   = unknown_wake_up;	ft_drive_type.name      = "Unknown";	ftape_timeout.seek      = 650 * FT_SECOND;	ftape_timeout.reset     = 670 * FT_SECOND;	ftape_timeout.rewind    = 650 * FT_SECOND;	ftape_timeout.head_seek =  15 * FT_SECOND;	ftape_timeout.stop      =   5 * FT_SECOND;	ftape_timeout.pause     =  16 * FT_SECOND;	ft_qic_std             = -1;	ftape_tape_len         = 0;  /* unknown */	ftape_current_command  = 0;	ftape_current_cylinder = -1;	ft_segments_per_track       = 102;	ftape_segments_per_head     = 1020;	ftape_segments_per_cylinder = 4;	ft_tracks_per_tape          = 20;	ft_failure = 1;	ft_formatted       = 0;	ft_no_tape         = 1;	ft_write_protected = 1;	ft_new_tape        = 1;	ft_driver_state = idle;	ft_data_rate = 		ft_fdc_max_rate   = 500;	ft_drive_max_rate = 0; /* triggers set_rate_test() */	ftape_init_drive_needed = 1;	ft_header_segment_1    = -1;	ft_header_segment_2    = -1;	ft_used_header_segment = -1;	ft_first_data_segment  = -1;	ft_last_data_segment   = -1;	ft_location.track = -1;	ft_location.known = 0;	ftape_tape_running = 0;	ftape_might_be_off_track = 1;	ftape_new_cartridge();	/* init some tape related variables */	ftape_init_bsm();	TRACE_EXIT;}

⌨️ 快捷键说明

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