cciss.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,278 行 · 第 1/5 页

C
2,278
字号
		/* Copy the error information out */ 		iocommand.error_info = *(c->err_info);		if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) )		{			kfree(buff);			cmd_free(host, c, 0);			return( -EFAULT);			} 			if (iocommand.Request.Type.Direction == XFER_READ)                {                        /* Copy the data out of the buffer we created */                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))			{                        	kfree(buff);				cmd_free(host, c, 0);				return -EFAULT;			}                }                kfree(buff);		cmd_free(host, c, 0);                return(0);	} 	case CCISS_BIG_PASSTHRU: {		BIG_IOCTL_Command_struct *ioc;		CommandList_struct *c;		unsigned char **buff = NULL;		int	*buff_size = NULL;		u64bit	temp64;		unsigned long flags;		BYTE sg_used = 0;		int status = 0;		int i;		DECLARE_COMPLETION(wait);		__u32   left;		__u32	sz;		BYTE    __user *data_ptr;		if (!arg)			return -EINVAL;		if (!capable(CAP_SYS_RAWIO))			return -EPERM;		ioc = (BIG_IOCTL_Command_struct *) 			kmalloc(sizeof(*ioc), GFP_KERNEL);		if (!ioc) {			status = -ENOMEM;			goto cleanup1;		}		if (copy_from_user(ioc, argp, sizeof(*ioc))) {			status = -EFAULT;			goto cleanup1;		}		if ((ioc->buf_size < 1) &&			(ioc->Request.Type.Direction != XFER_NONE)) {				status = -EINVAL;				goto cleanup1;		}		/* Check kmalloc limits  using all SGs */		if (ioc->malloc_size > MAX_KMALLOC_SIZE) {			status = -EINVAL;			goto cleanup1;		}		if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {			status = -EINVAL;			goto cleanup1;		}		buff = (unsigned char **) kmalloc(MAXSGENTRIES * 				sizeof(char *), GFP_KERNEL);		if (!buff) {			status = -ENOMEM;			goto cleanup1;		}		memset(buff, 0, MAXSGENTRIES);		buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int), 					GFP_KERNEL);		if (!buff_size) {			status = -ENOMEM;			goto cleanup1;		}		left = ioc->buf_size;		data_ptr = ioc->buf;		while (left) {			sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;			buff_size[sg_used] = sz;			buff[sg_used] = kmalloc(sz, GFP_KERNEL);			if (buff[sg_used] == NULL) {				status = -ENOMEM;				goto cleanup1;			}			if (ioc->Request.Type.Direction == XFER_WRITE &&				copy_from_user(buff[sg_used], data_ptr, sz)) {					status = -ENOMEM;					goto cleanup1;						} else {				memset(buff[sg_used], 0, sz);			}			left -= sz;			data_ptr += sz;			sg_used++;		}		if ((c = cmd_alloc(host , 0)) == NULL) {			status = -ENOMEM;			goto cleanup1;			}		c->cmd_type = CMD_IOCTL_PEND;		c->Header.ReplyQueue = 0;				if( ioc->buf_size > 0) {			c->Header.SGList = sg_used;			c->Header.SGTotal= sg_used;		} else { 			c->Header.SGList = 0;			c->Header.SGTotal= 0;		}		c->Header.LUN = ioc->LUN_info;		c->Header.Tag.lower = c->busaddr;				c->Request = ioc->Request;		if (ioc->buf_size > 0 ) {			int i;			for(i=0; i<sg_used; i++) {				temp64.val = pci_map_single( host->pdev, buff[i],					buff_size[i],					PCI_DMA_BIDIRECTIONAL);				c->SG[i].Addr.lower = temp64.val32.lower;				c->SG[i].Addr.upper = temp64.val32.upper;				c->SG[i].Len = buff_size[i];				c->SG[i].Ext = 0;  /* we are not chaining */			}		}		c->waiting = &wait;		/* Put the request on the tail of the request queue */		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);		addQ(&host->reqQ, c);		host->Qdepth++;		start_io(host);		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		wait_for_completion(&wait);		/* unlock the buffers from DMA */		for(i=0; i<sg_used; i++) {			temp64.val32.lower = c->SG[i].Addr.lower;			temp64.val32.upper = c->SG[i].Addr.upper;			pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,				buff_size[i], PCI_DMA_BIDIRECTIONAL);		}		/* Copy the error information out */		ioc->error_info = *(c->err_info);		if (copy_to_user(argp, ioc, sizeof(*ioc))) {			cmd_free(host, c, 0);			status = -EFAULT;			goto cleanup1;		}		if (ioc->Request.Type.Direction == XFER_READ) {			/* Copy the data out of the buffer we created */			BYTE __user *ptr = ioc->buf;	        	for(i=0; i< sg_used; i++) {				if (copy_to_user(ptr, buff[i], buff_size[i])) {					cmd_free(host, c, 0);					status = -EFAULT;					goto cleanup1;				}				ptr += buff_size[i];			}		}		cmd_free(host, c, 0);		status = 0;cleanup1:		if (buff) {			for(i=0; i<sg_used; i++)				if(buff[i] != NULL)					kfree(buff[i]);			kfree(buff);		}		if (buff_size)			kfree(buff_size);		if (ioc)			kfree(ioc);		return(status);	}	default:		return -EBADRQC;	}	}static int cciss_revalidate(struct gendisk *disk){	drive_info_struct *drv = disk->private_data;	set_capacity(disk, drv->nr_blocks);	return 0;}/* * revalidate_allvol is for online array config utilities.  After a * utility reconfigures the drives in the array, it can use this function * (through an ioctl) to make the driver zap any previous disk structs for * that controller and get new ones. * * Right now I'm using the getgeometry() function to do this, but this * function should probably be finer grained and allow you to revalidate one * particualar logical volume (instead of all of them on a particular * controller). */static int revalidate_allvol(ctlr_info_t *host){	int ctlr = host->ctlr, i;	unsigned long flags;        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);        if (host->usage_count > 1) {                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);                printk(KERN_WARNING "cciss: Device busy for volume"                        " revalidation (usage=%d)\n", host->usage_count);                return -EBUSY;        }        host->usage_count++;	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);	for(i=0; i< NWD; i++) {		struct gendisk *disk = host->gendisk[i];		if (disk->flags & GENHD_FL_UP)			del_gendisk(disk);	}        /*         * Set the partition and block size structures for all volumes         * on this controller to zero.  We will reread all of this data         */        memset(host->drv,        0, sizeof(drive_info_struct)						* CISS_MAX_LUN);        /*         * Tell the array controller not to give us any interrupts while         * we check the new geometry.  Then turn interrupts back on when         * we're done.         */        host->access.set_intr_mask(host, CCISS_INTR_OFF);        cciss_getgeometry(ctlr);        host->access.set_intr_mask(host, CCISS_INTR_ON);	/* Loop through each real device */ 	for (i = 0; i < NWD; i++) {		struct gendisk *disk = host->gendisk[i];		drive_info_struct *drv = &(host->drv[i]);		if (!drv->nr_blocks)			continue;		blk_queue_hardsect_size(host->queue, drv->block_size);		set_capacity(disk, drv->nr_blocks);		add_disk(disk);	}        host->usage_count--;        return 0;}static int deregister_disk(struct gendisk *disk){	unsigned long flags;	ctlr_info_t *h = get_host(disk);	drive_info_struct *drv = get_drv(disk);	int ctlr = h->ctlr;	if (!capable(CAP_SYS_RAWIO))		return -EPERM;	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	/* make sure logical volume is NOT is use */	if( drv->usage_count > 1) {		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);                return -EBUSY;	}	drv->usage_count++;	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);	/* invalidate the devices and deregister the disk */ 	if (disk->flags & GENHD_FL_UP)		del_gendisk(disk);	/* check to see if it was the last disk */	if (drv == h->drv + h->highest_lun) {		/* if so, find the new hightest lun */		int i, newhighest =-1;		for(i=0; i<h->highest_lun; i++) {			/* if the disk has size > 0, it is available */			if (h->drv[i].nr_blocks)				newhighest = i;		}		h->highest_lun = newhighest;					}	--h->num_luns;	/* zero out the disk size info */ 	drv->nr_blocks = 0;	drv->block_size = 0;	drv->cylinders = 0;	drv->LunID = 0;	return(0);}static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,	size_t size,	unsigned int use_unit_num, /* 0: address the controller,				      1: address logical volume log_unit,				      2: periph device address is scsi3addr */	unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr,	int cmd_type){	ctlr_info_t *h= hba[ctlr];	u64bit buff_dma_handle;	int status = IO_OK;	c->cmd_type = CMD_IOCTL_PEND;	c->Header.ReplyQueue = 0;	if( buff != NULL) {		c->Header.SGList = 1;		c->Header.SGTotal= 1;	} else {		c->Header.SGList = 0;                c->Header.SGTotal= 0;	}	c->Header.Tag.lower = c->busaddr;	c->Request.Type.Type = cmd_type;	if (cmd_type == TYPE_CMD) {		switch(cmd) {		case  CISS_INQUIRY:			/* If the logical unit number is 0 then, this is going			to controller so It's a physical command			mode = 0 target = 0.  So we have nothing to write.			otherwise, if use_unit_num == 1,			mode = 1(volume set addressing) target = LUNID			otherwise, if use_unit_num == 2,			mode = 0(periph dev addr) target = scsi3addr */			if (use_unit_num == 1) {				c->Header.LUN.LogDev.VolId=					h->drv[log_unit].LunID;                        	c->Header.LUN.LogDev.Mode = 1;			} else if (use_unit_num == 2) {				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);				c->Header.LUN.LogDev.Mode = 0;			}			/* are we trying to read a vital product page */			if(page_code != 0) {				c->Request.CDB[1] = 0x01;				c->Request.CDB[2] = page_code;			}			c->Request.CDBLen = 6;			c->Request.Type.Attribute = ATTR_SIMPLE;  			c->Request.Type.Direction = XFER_READ;			c->Request.Timeout = 0;			c->Request.CDB[0] =  CISS_INQUIRY;			c->Request.CDB[4] = size  & 0xFF;  		break;		case CISS_REPORT_LOG:		case CISS_REPORT_PHYS:                        /* Talking to controller so It's a physical command			   mode = 00 target = 0.  Nothing to write.                        */			c->Request.CDBLen = 12;			c->Request.Type.Attribute = ATTR_SIMPLE;			c->Request.Type.Direction = XFER_READ;			c->Request.Timeout = 0;			c->Request.CDB[0] = cmd;			c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB			c->Request.CDB[7] = (size >> 16) & 0xFF;			c->Request.CDB[8] = (size >> 8) & 0xFF;			c->Request.CDB[9] = size & 0xFF;			break;		case CCISS_READ_CAPACITY:			c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;			c->Header.LUN.LogDev.Mode = 1;			c->Request.CDBLen = 10;			c->Request.Type.Attribute = ATTR_SIMPLE;			c->Request.Type.Direction = XFER_READ;			c->Request.Timeout = 0;			c->Request.CDB[0] = cmd;		break;		case CCISS_CACHE_FLUSH:			c->Request.CDBLen = 12;			c->Request.Type.Attribute = ATTR_SIMPLE;			c->Request.Type.Direction = XFER_WRITE;			c->Request.Timeout = 0;			c->Request.CDB[0] = BMIC_WRITE;			c->Request.CDB[6] = BMIC_CACHE_FLUSH;		break;		default:			printk(KERN_WARNING				"cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);			return(IO_ERROR);		}	} else if (cmd_type == TYPE_MSG) {		switch (cmd) {		case 3:	/* No-Op message */			c->Request.CDBLen = 1;			c->Request.Type.Attribute = ATTR_SIMPLE;			c->Request.Type.Direction = XFER_WRITE;			c->Request.Timeout = 0;			c->Request.CDB[0] = cmd;			break;		default:			printk(KERN_WARNING				"cciss%d: unknown message type %d\n",				ctlr, cmd);			return IO_ERROR;		}	} else {		printk(KERN_WARNING			"cciss%d: unknown command type %d\n", ctlr, cmd_type);		return IO_ERROR;	}	/* Fill in the scatter gather information */	if (size > 0) {		buff_dma_handle.val = (__u64) pci_map_single(h->pdev,			buff, size, PCI_DMA_BIDIRECTIONAL);		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;		c->SG[0].Len = size;		c->SG[0].Ext = 0;  /* we are not chaining */	}	return status;}static int sendcmd_withirq(__u8	cmd,	int	ctlr,	void	*buff,	size_t	size,	unsigned int use_unit_num,	unsigned int log_unit,	__u8	page_code,	int cmd_type){	ctlr_info_t *h = hba[ctlr];	CommandList_struct *c;	u64bit	buff_dma_handle;	unsigned long flags;	int return_status;	DECLARE_COMPLETION(wait);		if ((c = cmd_alloc(h , 0)) == NULL)		return -ENOMEM;	return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,		log_unit, page_code, NULL, cmd_type);	if (return_status != IO_OK) {		cmd_free(h, c, 0);		return return_status;	}resend_cmd2:	c->waiting = &wait;		/* Put the request on the tail of the queue and send it */	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);	addQ(&h->reqQ, c);	h->Qdepth++;	start_io(h);	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		wait_for_completion(&wait);	if(c->err_info->CommandStatus != 0) 	{ /* an error has occurred */ 

⌨️ 快捷键说明

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