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

📄 acsi.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
				aip->changed = 1;			}		}	}	else {		printk( KERN_ERR "%s: Test for medium changed timed out; "				"assuming a change\n", disk->disk_name);		aip->changed = 1;	}	ENABLE_IRQ();	stdma_release();	/* Now, after reading a block, the changed status is surely valid. */	return aip->changed;}static int acsi_change_blk_size( int target, int lun){	int i;	for (i=0; i<12; i++)		acsi_buffer[i] = 0;	acsi_buffer[3] = 8;	acsi_buffer[10] = 2;	CMDSET_TARG_LUN( modeselect_cmd, target, lun);	if (!acsicmd_dma( modeselect_cmd, acsi_buffer, 1,1,0) ||		!acsi_wait_for_IRQ( 3*HZ ) ||		acsi_getstatus() != 0 ) {		return(0);	}	return(1);}static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ){	int page;	CMDSET_TARG_LUN( modesense_cmd, target, lun );	for (page=0; page<4; page++) {		modesense_cmd[2] = page;		if (!acsicmd_dma( modesense_cmd, acsi_buffer, 1, 0, 0 ) ||		    !acsi_wait_for_IRQ( 3*HZ ) ||		    acsi_getstatus())			continue;		/* read twice to jump over the second 16-byte border! */		udelay(300);		if (acsi_wait_for_noIRQ( 20 ) &&		    acsicmd_nodma( modesense_cmd, 0 ) &&		    acsi_wait_for_IRQ( 3*HZ ) &&		    acsi_getstatus() == 0)			break;	}	if (page == 4) {		return(0);	}	dma_cache_maintenance( phys_acsi_buffer, sizeof(SENSE_DATA), 0 );	*sd = *(SENSE_DATA *)acsi_buffer;	/* Validity check, depending on type of data */		switch( SENSE_TYPE(*sd) ) {	  case SENSE_TYPE_ATARI:		if (CAPACITY(*sd) == 0)			goto invalid_sense;		break;	  case SENSE_TYPE_SCSI:		if (sd->scsi.descriptor_size != 8)			goto invalid_sense;		break;	  case SENSE_TYPE_UNKNOWN:		printk( KERN_ERR "ACSI target %d, lun %d: Cannot interpret "				"sense data\n", target, lun ); 			  invalid_sense:#ifdef DEBUG		{	int i;		printk( "Mode sense data for ACSI target %d, lun %d seem not valid:",				target, lun );		for( i = 0; i < sizeof(SENSE_DATA); ++i )			printk( "%02x ", (unsigned char)acsi_buffer[i] );		printk( "\n" );		}#endif		return( 0 );	}			return( 1 );}/******************************************************************* * *  Initialization * ********************************************************************/extern struct block_device_operations acsi_fops;static struct gendisk *acsi_gendisk[MAX_DEV];#define MAX_SCSI_DEVICE_CODE 10static const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] ={ "Direct-Access    ", "Sequential-Access", "Printer          ", "Processor        ", "WORM             ", "CD-ROM           ", "Scanner          ", "Optical Device   ", "Medium Changer   ", "Communications   "};static void print_inquiry(unsigned char *data){	int i;	printk(KERN_INFO "  Vendor: ");	for (i = 8; i < 16; i++)		{	        if (data[i] >= 0x20 && i < data[4] + 5)			printk("%c", data[i]);		else			printk(" ");		}	printk("  Model: ");	for (i = 16; i < 32; i++)		{	        if (data[i] >= 0x20 && i < data[4] + 5)			printk("%c", data[i]);		else			printk(" ");		}	printk("  Rev: ");	for (i = 32; i < 36; i++)		{	        if (data[i] >= 0x20 && i < data[4] + 5)			printk("%c", data[i]);		else			printk(" ");		}	printk("\n");	i = data[0] & 0x1f;	printk(KERN_INFO "  Type:   %s ", (i < MAX_SCSI_DEVICE_CODE									   ? scsi_device_types[i]									   : "Unknown          "));	printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);	if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)	  printk(" CCS\n");	else	  printk("\n");}/*  * Changes by Martin Rogge, 9th Aug 1995:  * acsi_devinit has been taken out of acsi_geninit, because it needs  * to be called from revalidate_acsidisk. The result of request sense  * is now checked for DRIVE NOT READY. * * The structure *aip is only valid when acsi_devinit returns  * DEV_SUPPORTED.  * */	#define DEV_NONE	0#define DEV_UNKNOWN	1#define DEV_SUPPORTED	2#define DEV_SLM		3static int acsi_devinit(struct acsi_info_struct *aip){	int status, got_inquiry;	SENSE_DATA sense;	unsigned char reqsense, extsense;	/*****************************************************************/	/* Do a TEST UNIT READY command to test the presence of a device */	/*****************************************************************/	CMDSET_TARG_LUN(tur_cmd, aip->target, aip->lun);	if (!acsicmd_nodma(tur_cmd, 0)) {		/* timed out -> no device here */#ifdef DEBUG_DETECT		printk("target %d lun %d: timeout\n", aip->target, aip->lun);#endif		return DEV_NONE;	}			/*************************/	/* Read the ACSI status. */	/*************************/	status = acsi_getstatus();	if (status) {		if (status == 0x12) {			/* The SLM printer should be the only device that			 * responds with the error code in the status byte. In			 * correct status bytes, bit 4 is never set.			 */			printk( KERN_INFO "Detected SLM printer at id %d lun %d\n",			       aip->target, aip->lun);			return DEV_SLM;		}		/* ignore CHECK CONDITION, since some devices send a		   UNIT ATTENTION */		if ((status & 0x1e) != 0x2) {#ifdef DEBUG_DETECT			printk("target %d lun %d: status %d\n",			       aip->target, aip->lun, status);#endif			return DEV_UNKNOWN;		}	}	/*******************************/	/* Do a REQUEST SENSE command. */	/*******************************/	if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) {		printk( KERN_WARNING "acsi_reqsense failed\n");		acsi_buffer[0] = 0;		acsi_buffer[2] = UNIT_ATTENTION;	}	reqsense = acsi_buffer[0];	extsense = acsi_buffer[2] & 0xf;	if (status) {		if ((reqsense & 0x70) == 0x70) {	/* extended sense */			if (extsense != UNIT_ATTENTION &&			    extsense != NOT_READY) {#ifdef DEBUG_DETECT				printk("target %d lun %d: extended sense %d\n",				       aip->target, aip->lun, extsense);#endif				return DEV_UNKNOWN;			}		}		else {			if (reqsense & 0x7f) {#ifdef DEBUG_DETECT				printk("target %d lun %d: sense %d\n",				       aip->target, aip->lun, reqsense);#endif				return DEV_UNKNOWN;			}		}	}	else 		if (reqsense == 0x4) {	/* SH204 Bug workaround */#ifdef DEBUG_DETECT			printk("target %d lun %d status=0 sense=4\n",			       aip->target, aip->lun);#endif			return DEV_UNKNOWN;		}	/***********************************************************/	/* Do an INQUIRY command to get more infos on this device. */	/***********************************************************/	/* Assume default values */	aip->removable = 1;	aip->read_only = 0;	aip->old_atari_disk = 0;	aip->changed = (extsense == NOT_READY);	/* medium inserted? */	aip->size = DEFAULT_SIZE;	got_inquiry = 0;	/* Fake inquiry result for old atari disks */	memcpy(acsi_buffer, "\000\000\001\000    Adaptec 40xx"	       "                    ", 40);	CMDSET_TARG_LUN(inquiry_cmd, aip->target, aip->lun);	if (acsicmd_dma(inquiry_cmd, acsi_buffer, 1, 0, 0) &&	    acsi_getstatus() == 0) {		acsicmd_nodma(inquiry_cmd, 0);		acsi_getstatus();		dma_cache_maintenance( phys_acsi_buffer, 256, 0 );		got_inquiry = 1;		aip->removable = !!(acsi_buffer[1] & 0x80);	}	if (aip->type == NONE)	/* only at boot time */		print_inquiry(acsi_buffer);	switch(acsi_buffer[0]) {	  case TYPE_DISK:		aip->type = HARDDISK;		break;	  case TYPE_ROM:		aip->type = CDROM;		aip->read_only = 1;		break;	  default:		return DEV_UNKNOWN;	}	/****************************/	/* Do a MODE SENSE command. */	/****************************/	if (!acsi_mode_sense(aip->target, aip->lun, &sense)) {		printk( KERN_WARNING "No mode sense data.\n" );		return DEV_UNKNOWN;	}	if ((SECTOR_SIZE(sense) != 512) &&	    ((aip->type != CDROM) ||	     !acsi_change_blk_size(aip->target, aip->lun) ||	     !acsi_mode_sense(aip->target, aip->lun, &sense) ||	     (SECTOR_SIZE(sense) != 512))) {		printk( KERN_WARNING "Sector size != 512 not supported.\n" );		return DEV_UNKNOWN;	}	/* There are disks out there that claim to have 0 sectors... */	if (CAPACITY(sense))		aip->size = CAPACITY(sense);	/* else keep DEFAULT_SIZE */	if (!got_inquiry && SENSE_TYPE(sense) == SENSE_TYPE_ATARI) {		/* If INQUIRY failed and the sense data suggest an old		 * Atari disk (SH20x, Megafile), the disk is not removable		 */		aip->removable = 0;		aip->old_atari_disk = 1;	}		/******************/	/* We've done it. */	/******************/		return DEV_SUPPORTED;}EXPORT_SYMBOL(acsi_delay_start);EXPORT_SYMBOL(acsi_delay_end);EXPORT_SYMBOL(acsi_wait_for_IRQ);EXPORT_SYMBOL(acsi_wait_for_noIRQ);EXPORT_SYMBOL(acsicmd_nodma);EXPORT_SYMBOL(acsi_getstatus);EXPORT_SYMBOL(acsi_buffer);EXPORT_SYMBOL(phys_acsi_buffer);#ifdef CONFIG_ATARI_SLM_MODULEvoid acsi_attach_SLMs( int (*attach_func)( int, int ) );EXPORT_SYMBOL(acsi_extstatus);EXPORT_SYMBOL(acsi_end_extstatus);EXPORT_SYMBOL(acsi_extcmd);EXPORT_SYMBOL(acsi_attach_SLMs);/* to remember IDs of SLM devices, SLM module is loaded later * (index is target#, contents is lun#, -1 means "no SLM") */int SLM_devices[8];#endifstatic struct block_device_operations acsi_fops = {	.owner		= THIS_MODULE,	.open		= acsi_open,	.release	= acsi_release,	.ioctl		= acsi_ioctl,	.media_changed	= acsi_media_change,	.revalidate_disk= acsi_revalidate,};#ifdef CONFIG_ATARI_SLM_MODULE/* call attach_slm() for each device that is a printer; needed for init of SLM * driver as a module, since it's not yet present if acsi.c is inited and thus * the bus gets scanned. */void acsi_attach_SLMs( int (*attach_func)( int, int ) ){	int i, n = 0;	for( i = 0; i < 8; ++i )		if (SLM_devices[i] >= 0)			n += (*attach_func)( i, SLM_devices[i] );	printk( KERN_INFO "Found %d SLM printer(s) total.\n", n );}#endif /* CONFIG_ATARI_SLM_MODULE */int acsi_init( void ){	int err = 0;	int i, target, lun;	struct acsi_info_struct *aip;#ifdef CONFIG_ATARI_SLM	int n_slm = 0;#endif	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI))		return 0;	if (register_blkdev(ACSI_MAJOR, "ad")) {		err = -EBUSY;		goto out1;	}	if (!(acsi_buffer =		  (char *)atari_stram_alloc(ACSI_BUFFER_SIZE, "acsi"))) {		err = -ENOMEM;		printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" );		goto out2;	}	phys_acsi_buffer = virt_to_phys( acsi_buffer );	STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000;		acsi_queue = blk_init_queue(do_acsi_request, &acsi_lock);	if (!acsi_queue) {		err = -ENOMEM;		goto out2a;	}#ifdef CONFIG_ATARI_SLM	err = slm_init();#endif	if (err)		goto out3;	printk( KERN_INFO "Probing ACSI devices:\n" );	NDevices = 0;#ifdef CONFIG_ATARI_SLM_MODULE	for( i = 0; i < 8; ++i )		SLM_devices[i] = -1;#endif	stdma_lock(NULL, NULL);	for (target = 0; target < 8 && NDevices < MAX_DEV; ++target) {		lun = 0;		do {			aip = &acsi_info[NDevices];			aip->type = NONE;			aip->target = target;			aip->lun = lun;			i = acsi_devinit(aip);			switch (i) {			  case DEV_SUPPORTED:				printk( KERN_INFO "Detected ");				switch (aip->type) {				  case HARDDISK:					printk("disk");					break;				  case CDROM:					printk("cdrom");					break;				  default:				}				printk(" ad%c at id %d lun %d ",				       'a' + NDevices, target, lun);				if (aip->removable) 					printk("(removable) ");				if (aip->read_only) 					printk("(read-only) ");				if (aip->size == DEFAULT_SIZE)					printk(" unkown size, using default ");				printk("%ld MByte\n",				       (aip->size*512+1024*1024/2)/(1024*1024));				NDevices++;				break;			  case DEV_SLM:#ifdef CONFIG_ATARI_SLM				n_slm += attach_slm( target, lun );				break;#endif#ifdef CONFIG_ATARI_SLM_MODULE				SLM_devices[target] = lun;				break;#endif				/* neither of the above: fall through to unknown device */			  case DEV_UNKNOWN:				printk( KERN_INFO "Detected unsupported device at "						"id %d lun %d\n", target, lun);				break;			}		}#ifdef CONFIG_ACSI_MULTI_LUN		while (i != DEV_NONE && ++lun < MAX_LUN);#else		while (0);#endif	}	/* reenable interrupt */	ENABLE_IRQ();	stdma_release();#ifndef CONFIG_ATARI_SLM	printk( KERN_INFO "Found %d ACSI device(s) total.\n", NDevices );#else	printk( KERN_INFO "Found %d ACSI device(s) and %d SLM printer(s) total.\n",			NDevices, n_slm );#endif	err = -ENOMEM;	for( i = 0; i < NDevices; ++i ) {		acsi_gendisk[i] = alloc_disk(16);		if (!acsi_gendisk[i])			goto out4;	}	for( i = 0; i < NDevices; ++i ) {		struct gendisk *disk = acsi_gendisk[i];		sprintf(disk->disk_name, "ad%c", 'a'+i);		aip = &acsi_info[NDevices];		sprintf(disk->devfs_name, "ad/target%d/lun%d", aip->target, aip->lun);		disk->major = ACSI_MAJOR;		disk->first_minor = i << 4;		if (acsi_info[i].type != HARDDISK) {			disk->minors = 1;			strcat(disk->devfs_name, "/disc");		}		disk->fops = &acsi_fops;		disk->private_data = &acsi_info[i];		set_capacity(disk, acsi_info[i].size);		disk->queue = acsi_queue;		add_disk(disk);	}	return 0;out4:	while (i--)		put_disk(acsi_gendisk[i]);out3:	blk_cleanup_queue(acsi_queue);out2a:	atari_stram_free( acsi_buffer );out2:	unregister_blkdev( ACSI_MAJOR, "ad" );out1:	return err;}#ifdef MODULEMODULE_LICENSE("GPL");int init_module(void){	int err;	if ((err = acsi_init()))		return( err );	printk( KERN_INFO "ACSI driver loaded as module.\n");	return( 0 );}void cleanup_module(void){	int i;	del_timer( &acsi_timer );	blk_cleanup_queue(acsi_queue);	atari_stram_free( acsi_buffer );	if (unregister_blkdev( ACSI_MAJOR, "ad" ) != 0)		printk( KERN_ERR "acsi: cleanup_module failed\n");	for (i = 0; i < NDevices; i++) {		del_gendisk(acsi_gendisk[i]);		put_disk(acsi_gendisk[i]);	}}#endif/* * This routine is called to flush all partitions and partition tables * for a changed scsi disk, and then re-read the new partition table. * If we are revalidating a disk because of a media change, then we * enter with usage == 0.  If we are using an ioctl, we automatically have * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. * * Changes by Martin Rogge, 9th Aug 1995:  * got cd-roms to work by calling acsi_devinit. There are only two problems: * First, if there is no medium inserted, the status will remain "changed". * That is no problem at all, but our design of three-valued logic (medium * changed, medium not changed, no medium inserted). * Secondly the check could fail completely and the drive could deliver * nonsensical data, which could mess up the acsi_info[] structure. In * that case we try to make the entry safe. * */static int acsi_revalidate(struct gendisk *disk){	struct acsi_info_struct *aip = disk->private_data;	stdma_lock( NULL, NULL );	if (acsi_devinit(aip) != DEV_SUPPORTED) {		printk( KERN_ERR "ACSI: revalidate failed for target %d lun %d\n",		       aip->target, aip->lun);		aip->size = 0;		aip->read_only = 1;		aip->removable = 1;		aip->changed = 1; /* next acsi_open will try again... */	}	ENABLE_IRQ();	stdma_release();	set_capacity(disk, aip->size);	return 0;}

⌨️ 快捷键说明

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