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

📄 acsi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (DEVICE_INTR)		return;  repeat:	CLEAR_TIMER();	/* Another check here: An interrupt or timer event could have	 * happened since the last check!	 */	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) {		if (!DEVICE_INTR) {			ENABLE_IRQ();			stdma_release();		}		return;	}	if (DEVICE_INTR)		return;	if (QUEUE_EMPTY) {		CLEAR_INTR;		ENABLE_IRQ();		stdma_release();		return;	}		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)		panic(DEVICE_NAME ": request list destroyed");	if (CURRENT->bh) {		if (!CURRENT->bh && !buffer_locked(CURRENT->bh))			panic(DEVICE_NAME ": block not locked");	}	dev = MINOR(CURRENT->rq_dev);	block = CURRENT->sector;	if (DEVICE_NR(dev) >= NDevices ||		block+CURRENT->nr_sectors >= acsi_part[dev].nr_sects) {#ifdef DEBUG		printk( "ad%c: attempted access for blocks %d...%ld past end of device at block %ld.\n",		       DEVICE_NR(dev)+'a',		       block, block + CURRENT->nr_sectors - 1,		       acsi_part[dev].nr_sects);#endif		end_request(0);		goto repeat;	}	if (acsi_info[DEVICE_NR(dev)].changed) {		printk( KERN_NOTICE "ad%c: request denied because cartridge has "				"been changed.\n", DEVICE_NR(dev)+'a' );		end_request(0);		goto repeat;	}		block += acsi_part[dev].start_sect;	target = acsi_info[DEVICE_NR(dev)].target;	lun    = acsi_info[DEVICE_NR(dev)].lun;	/* Find out how many sectors should be transferred from/to	 * consecutive buffers and thus can be done with a single command.	 */	buffer      = CURRENT->buffer;	pbuffer     = virt_to_phys(buffer);	nsect       = CURRENT->current_nr_sectors;	CurrentNReq = 1;	if ((bh = CURRENT->bh) && bh != CURRENT->bhtail) {		if (!STRAM_ADDR(pbuffer)) {			/* If transfer is done via the ACSI buffer anyway, we can			 * assemble as much bh's as fit in the buffer.			 */			while( (bh = bh->b_reqnext) ) {				if (nsect + (bh->b_size>>9) > ACSI_BUFFER_SECTORS) break;				nsect += bh->b_size >> 9;				++CurrentNReq;				if (bh == CURRENT->bhtail) break;			}			buffer = acsi_buffer;			pbuffer = phys_acsi_buffer;		}		else {			unsigned long pendadr, pnewadr;			pendadr = pbuffer + nsect*512;			while( (bh = bh->b_reqnext) ) {				pnewadr = virt_to_phys(bh->b_data);				if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break;				nsect += bh->b_size >> 9;				pendadr = pnewadr + bh->b_size;				++CurrentNReq;				if (bh == CURRENT->bhtail) break;			}		}	}	else {		if (!STRAM_ADDR(pbuffer)) {			buffer = acsi_buffer;			pbuffer = phys_acsi_buffer;			if (nsect > ACSI_BUFFER_SECTORS)				nsect = ACSI_BUFFER_SECTORS;		}	}	CurrentBuffer = buffer;	CurrentNSect  = nsect;		if (CURRENT->cmd == WRITE) {		CMDSET_TARG_LUN( write_cmd, target, lun );		CMDSET_BLOCK( write_cmd, block );		CMDSET_LEN( write_cmd, nsect );		if (buffer == acsi_buffer)			copy_to_acsibuffer();		dma_cache_maintenance( pbuffer, nsect*512, 1 );		SET_INTR(write_intr);		if (!acsicmd_dma( write_cmd, buffer, nsect, 1, 1)) {			CLEAR_INTR;			printk( KERN_ERR "ACSI (write): Timeout in command block\n" );			bad_rw_intr();			goto repeat;		}		SET_TIMER();		return;	}	if (CURRENT->cmd == READ) {		CMDSET_TARG_LUN( read_cmd, target, lun );		CMDSET_BLOCK( read_cmd, block );		CMDSET_LEN( read_cmd, nsect );		SET_INTR(read_intr);		if (!acsicmd_dma( read_cmd, buffer, nsect, 0, 1)) {			CLEAR_INTR;			printk( KERN_ERR "ACSI (read): Timeout in command block\n" );			bad_rw_intr();			goto repeat;		}		SET_TIMER();		return;	}	panic("unknown ACSI command");}/*********************************************************************** * *  Misc functions: ioctl, open, release, check_change, ... * ***********************************************************************/static int acsi_ioctl( struct inode *inode, struct file *file,					   unsigned int cmd, unsigned long arg ){	int dev;	if (!inode)		return -EINVAL;	dev = DEVICE_NR(MINOR(inode->i_rdev));	if (dev >= NDevices)		return -EINVAL;	switch (cmd) {	  case HDIO_GETGEO:		/* HDIO_GETGEO is supported more for getting the partition's		 * start sector... */	  { struct hd_geometry *geo = (struct hd_geometry *)arg;	    /* just fake some geometry here, it's nonsense anyway; to make it		 * easy, use Adaptec's usual 64/32 mapping */	    put_user( 64, &geo->heads );	    put_user( 32, &geo->sectors );	    put_user( acsi_info[dev].size >> 11, &geo->cylinders );		put_user( acsi_part[MINOR(inode->i_rdev)].start_sect, &geo->start );		return 0;	  }			  case SCSI_IOCTL_GET_IDLUN:		/* SCSI compatible GET_IDLUN call to get target's ID and LUN number */		put_user( acsi_info[dev].target | (acsi_info[dev].lun << 8),				  &((Scsi_Idlun *) arg)->dev_id );		put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id );		return 0;			  case BLKGETSIZE:   /* Return device size */		return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects,				(long *) arg);	  case BLKROSET:	  case BLKROGET:	  case BLKFLSBUF:	  case BLKPG:		return blk_ioctl(inode->i_rdev, cmd, arg);	  case BLKRRPART: /* Re-read partition tables */	        if (!capable(CAP_SYS_ADMIN)) 			return -EACCES;		return revalidate_acsidisk(inode->i_rdev, 1);	  default:		return -EINVAL;	}}/* * Open a device, check for read-only and lock the medium if it is * removable. * * Changes by Martin Rogge, 9th Aug 1995: * Check whether check_disk_change (and therefore revalidate_acsidisk) * was successful. They fail when there is no medium in the drive. * * The problem of media being changed during an operation can be  * ignored because of the prevent_removal code. * * Added check for the validity of the device number. * */static int acsi_open( struct inode * inode, struct file * filp ){	int  device;	struct acsi_info_struct *aip;	device = DEVICE_NR(MINOR(inode->i_rdev));	if (device >= NDevices)		return -ENXIO;	aip = &acsi_info[device];	while (busy[device])		sleep_on(&busy_wait);	if (access_count[device] == 0 && aip->removable) {#if 0		aip->changed = 1;	/* safety first */#endif		check_disk_change( inode->i_rdev );		if (aip->changed)	/* revalidate was not successful (no medium) */			return -ENXIO;		acsi_prevent_removal(device, 1);	}	access_count[device]++;	MOD_INC_USE_COUNT;	if (filp && filp->f_mode) {		check_disk_change( inode->i_rdev );		if (filp->f_mode & 2) {			if (aip->read_only) {				acsi_release( inode, filp );				return -EROFS;			}		}	}	return 0;}/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */static int acsi_release( struct inode * inode, struct file * file ){	int device = DEVICE_NR(MINOR(inode->i_rdev));	if (--access_count[device] == 0 && acsi_info[device].removable)		acsi_prevent_removal(device, 0);	MOD_DEC_USE_COUNT;	return( 0 );}/* * Prevent or allow a media change for removable devices. */static void acsi_prevent_removal(int device, int flag){	stdma_lock( NULL, NULL );		CMDSET_TARG_LUN(pa_med_rem_cmd, acsi_info[device].target,			acsi_info[device].lun);	CMDSET_LEN( pa_med_rem_cmd, flag );		if (acsicmd_nodma(pa_med_rem_cmd, 0) && acsi_wait_for_IRQ(3*HZ))		acsi_getstatus();	/* Do not report errors -- some devices may not know this command. */	ENABLE_IRQ();	stdma_release();}static int acsi_media_change (dev_t dev){	int device = DEVICE_NR(MINOR(dev));	struct acsi_info_struct *aip;	aip = &acsi_info[device];	if (!aip->removable) 		return 0;	if (aip->changed)		/* We can be sure that the medium has been changed -- REQUEST		 * SENSE has reported this earlier.		 */		return 1;	/* If the flag isn't set, make a test by reading block 0.	 * If errors happen, it seems to be better to say "changed"...	 */	stdma_lock( NULL, NULL );	CMDSET_TARG_LUN(read_cmd, aip->target, aip->lun);	CMDSET_BLOCK( read_cmd, 0 );	CMDSET_LEN( read_cmd, 1 );	if (acsicmd_dma(read_cmd, acsi_buffer, 1, 0, 0) &&	    acsi_wait_for_IRQ(3*HZ)) {		if (acsi_getstatus()) {			if (acsi_reqsense(acsi_buffer, aip->target, aip->lun)) {				if (CARTRCH_STAT(device, acsi_buffer))					aip->changed = 1;			}			else {				printk( KERN_ERR "ad%c: REQUEST SENSE failed in test for "				       "medium change; assuming a change\n", device + 'a' );				aip->changed = 1;			}		}	}	else {		printk( KERN_ERR "ad%c: Test for medium changed timed out; "				"assuming a change\n", device + 'a');		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 = {	MAJOR_NR,		/* Major number */		"ad",			/* Major name */	4,			/* Bits to shift to get real from partition */	1 << 4,			/* Number of partitions per real */	acsi_part,		/* hd struct */	acsi_sizes,		/* block sizes */	0,			/* number */	(void *)acsi_info,	/* internal */	NULL,			/* next */	&acsi_fops,		/* file operations */};	#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]);

⌨️ 快捷键说明

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