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

📄 megaraid_sas.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		goto fail_irq;	}	megasas_enable_intr(instance->reg_set);	/*	 * Store instance in PCI softstate	 */	pci_set_drvdata(pdev, instance);	/*	 * Add this controller to megasas_mgmt_info structure so that it	 * can be exported to management applications	 */	megasas_mgmt_info.count++;	megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;	megasas_mgmt_info.max_index++;	/*	 * Initiate AEN (Asynchronous Event Notification)	 */	if (megasas_start_aen(instance)) {		printk(KERN_DEBUG "megasas: start aen failed\n");		goto fail_start_aen;	}	/*	 * Register with SCSI mid-layer	 */	if (megasas_io_attach(instance))		goto fail_io_attach;	return 0;      fail_start_aen:      fail_io_attach:	megasas_mgmt_info.count--;	megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;	megasas_mgmt_info.max_index--;	pci_set_drvdata(pdev, NULL);	megasas_disable_intr(instance->reg_set);	free_irq(instance->pdev->irq, instance);	megasas_release_mfi(instance);      fail_irq:      fail_init_mfi:      fail_alloc_dma_buf:	if (instance->evt_detail)		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),				    instance->evt_detail,				    instance->evt_detail_h);	if (instance->producer)		pci_free_consistent(pdev, sizeof(u32), instance->producer,				    instance->producer_h);	if (instance->consumer)		pci_free_consistent(pdev, sizeof(u32), instance->consumer,				    instance->consumer_h);	scsi_host_put(host);      fail_alloc_instance:      fail_set_dma_mask:	pci_disable_device(pdev);	return -ENODEV;}/** * megasas_flush_cache -	Requests FW to flush all its caches * @instance:			Adapter soft state */static void megasas_flush_cache(struct megasas_instance *instance){	struct megasas_cmd *cmd;	struct megasas_dcmd_frame *dcmd;	cmd = megasas_get_cmd(instance);	if (!cmd)		return;	dcmd = &cmd->frame->dcmd;	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);	dcmd->cmd = MFI_CMD_DCMD;	dcmd->cmd_status = 0x0;	dcmd->sge_count = 0;	dcmd->flags = MFI_FRAME_DIR_NONE;	dcmd->timeout = 0;	dcmd->data_xfer_len = 0;	dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;	dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;	megasas_issue_blocked_cmd(instance, cmd);	megasas_return_cmd(instance, cmd);	return;}/** * megasas_shutdown_controller -	Instructs FW to shutdown the controller * @instance:				Adapter soft state */static void megasas_shutdown_controller(struct megasas_instance *instance){	struct megasas_cmd *cmd;	struct megasas_dcmd_frame *dcmd;	cmd = megasas_get_cmd(instance);	if (!cmd)		return;	if (instance->aen_cmd)		megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);	dcmd = &cmd->frame->dcmd;	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);	dcmd->cmd = MFI_CMD_DCMD;	dcmd->cmd_status = 0x0;	dcmd->sge_count = 0;	dcmd->flags = MFI_FRAME_DIR_NONE;	dcmd->timeout = 0;	dcmd->data_xfer_len = 0;	dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;	megasas_issue_blocked_cmd(instance, cmd);	megasas_return_cmd(instance, cmd);	return;}/** * megasas_detach_one -	PCI hot"un"plug entry point * @pdev:		PCI device structure */static void megasas_detach_one(struct pci_dev *pdev){	int i;	struct Scsi_Host *host;	struct megasas_instance *instance;	instance = pci_get_drvdata(pdev);	host = instance->host;	scsi_remove_host(instance->host);	megasas_flush_cache(instance);	megasas_shutdown_controller(instance);	/*	 * Take the instance off the instance array. Note that we will not	 * decrement the max_index. We let this array be sparse array	 */	for (i = 0; i < megasas_mgmt_info.max_index; i++) {		if (megasas_mgmt_info.instance[i] == instance) {			megasas_mgmt_info.count--;			megasas_mgmt_info.instance[i] = NULL;			break;		}	}	pci_set_drvdata(instance->pdev, NULL);	megasas_disable_intr(instance->reg_set);	free_irq(instance->pdev->irq, instance);	megasas_release_mfi(instance);	pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),			    instance->evt_detail, instance->evt_detail_h);	pci_free_consistent(pdev, sizeof(u32), instance->producer,			    instance->producer_h);	pci_free_consistent(pdev, sizeof(u32), instance->consumer,			    instance->consumer_h);	scsi_host_put(host);	pci_set_drvdata(pdev, NULL);	pci_disable_device(pdev);	return;}/** * megasas_shutdown -	Shutdown entry point * @device:		Generic device structure */static void megasas_shutdown(struct pci_dev *pdev){	struct megasas_instance *instance = pci_get_drvdata(pdev);	megasas_flush_cache(instance);}/** * megasas_mgmt_open -	char node "open" entry point */static int megasas_mgmt_open(struct inode *inode, struct file *filep){	/*	 * Allow only those users with admin rights	 */	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	return 0;}/** * megasas_mgmt_release - char node "release" entry point */static int megasas_mgmt_release(struct inode *inode, struct file *filep){	filep->private_data = NULL;	fasync_helper(-1, filep, 0, &megasas_async_queue);	return 0;}/** * megasas_mgmt_fasync -	Async notifier registration from applications * * This function adds the calling process to a driver global queue. When an * event occurs, SIGIO will be sent to all processes in this queue. */static int megasas_mgmt_fasync(int fd, struct file *filep, int mode){	int rc;	down(&megasas_async_queue_mutex);	rc = fasync_helper(fd, filep, mode, &megasas_async_queue);	up(&megasas_async_queue_mutex);	if (rc >= 0) {		/* For sanity check when we get ioctl */		filep->private_data = filep;		return 0;	}	printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc);	return rc;}/** * megasas_mgmt_fw_ioctl -	Issues management ioctls to FW * @instance:			Adapter soft state * @argp:			User's ioctl packet */static intmegasas_mgmt_fw_ioctl(struct megasas_instance *instance,		      struct megasas_iocpacket __user * user_ioc,		      struct megasas_iocpacket *ioc){	struct megasas_sge32 *kern_sge32;	struct megasas_cmd *cmd;	void *kbuff_arr[MAX_IOCTL_SGE];	dma_addr_t buf_handle = 0;	int error = 0, i;	void *sense = NULL;	dma_addr_t sense_handle;	u32 *sense_ptr;	memset(kbuff_arr, 0, sizeof(kbuff_arr));	if (ioc->sge_count > MAX_IOCTL_SGE) {		printk(KERN_DEBUG "megasas: SGE count [%d] >  max limit [%d]\n",		       ioc->sge_count, MAX_IOCTL_SGE);		return -EINVAL;	}	cmd = megasas_get_cmd(instance);	if (!cmd) {		printk(KERN_DEBUG "megasas: Failed to get a cmd packet\n");		return -ENOMEM;	}	/*	 * User's IOCTL packet has 2 frames (maximum). Copy those two	 * frames into our cmd's frames. cmd->frame's context will get	 * overwritten when we copy from user's frames. So set that value	 * alone separately	 */	memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);	cmd->frame->hdr.context = cmd->index;	/*	 * The management interface between applications and the fw uses	 * MFI frames. E.g, RAID configuration changes, LD property changes	 * etc are accomplishes through different kinds of MFI frames. The	 * driver needs to care only about substituting user buffers with	 * kernel buffers in SGLs. The location of SGL is embedded in the	 * struct iocpacket itself.	 */	kern_sge32 = (struct megasas_sge32 *)	    ((unsigned long)cmd->frame + ioc->sgl_off);	/*	 * For each user buffer, create a mirror buffer and copy in	 */	for (i = 0; i < ioc->sge_count; i++) {		kbuff_arr[i] = pci_alloc_consistent(instance->pdev,						    ioc->sgl[i].iov_len,						    &buf_handle);		if (!kbuff_arr[i]) {			printk(KERN_DEBUG "megasas: Failed to alloc "			       "kernel SGL buffer for IOCTL \n");			error = -ENOMEM;			goto out;		}		/*		 * We don't change the dma_coherent_mask, so		 * pci_alloc_consistent only returns 32bit addresses		 */		kern_sge32[i].phys_addr = (u32) buf_handle;		kern_sge32[i].length = ioc->sgl[i].iov_len;		/*		 * We created a kernel buffer corresponding to the		 * user buffer. Now copy in from the user buffer		 */		if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,				   (u32) (ioc->sgl[i].iov_len))) {			error = -EFAULT;			goto out;		}	}	if (ioc->sense_len) {		sense = pci_alloc_consistent(instance->pdev, ioc->sense_len,					     &sense_handle);		if (!sense) {			error = -ENOMEM;			goto out;		}		sense_ptr =		    (u32 *) ((unsigned long)cmd->frame + ioc->sense_off);		*sense_ptr = sense_handle;	}	/*	 * Set the sync_cmd flag so that the ISR knows not to complete this	 * cmd to the SCSI mid-layer	 */	cmd->sync_cmd = 1;	megasas_issue_blocked_cmd(instance, cmd);	cmd->sync_cmd = 0;	/*	 * copy out the kernel buffers to user buffers	 */	for (i = 0; i < ioc->sge_count; i++) {		if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],				 ioc->sgl[i].iov_len)) {			error = -EFAULT;			goto out;		}	}	/*	 * copy out the sense	 */	if (ioc->sense_len) {		/*		 * sense_ptr points to the location that has the user		 * sense buffer address		 */		sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +				     ioc->sense_off);		if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),				 sense, ioc->sense_len)) {			error = -EFAULT;			goto out;		}	}	/*	 * copy the status codes returned by the fw	 */	if (copy_to_user(&user_ioc->frame.hdr.cmd_status,			 &cmd->frame->hdr.cmd_status, sizeof(u8))) {		printk(KERN_DEBUG "megasas: Error copying out cmd_status\n");		error = -EFAULT;	}      out:	if (sense) {		pci_free_consistent(instance->pdev, ioc->sense_len,				    sense, sense_handle);	}	for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {		pci_free_consistent(instance->pdev,				    kern_sge32[i].length,				    kbuff_arr[i], kern_sge32[i].phys_addr);	}	megasas_return_cmd(instance, cmd);	return error;}static struct megasas_instance *megasas_lookup_instance(u16 host_no){	int i;	for (i = 0; i < megasas_mgmt_info.max_index; i++) {		if ((megasas_mgmt_info.instance[i]) &&		    (megasas_mgmt_info.instance[i]->host->host_no == host_no))			return megasas_mgmt_info.instance[i];	}	return NULL;}static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg){	struct megasas_iocpacket __user *user_ioc =	    (struct megasas_iocpacket __user *)arg;	struct megasas_iocpacket *ioc;	struct megasas_instance *instance;	int error;	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);	if (!ioc)		return -ENOMEM;	if (copy_from_user(ioc, user_ioc, sizeof(*ioc))) {		error = -EFAULT;		goto out_kfree_ioc;	}	instance = megasas_lookup_instance(ioc->host_no);	if (!instance) {		error = -ENODEV;		goto out_kfree_ioc;	}	/*	 * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds	 */	if (down_interruptible(&instance->ioctl_sem)) {		error = -ERESTARTSYS;		goto out_kfree_ioc;	}	error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);	up(&instance->ioctl_sem);      out_kfree_ioc:	kfree(ioc);	return error;}static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg){	struct megasas_instance *instance;	struct megasas_aen aen;	int error;	if (file->private_data != file) {		printk(KERN_DEBUG "megasas: fasync_helper was not "		       "called first\n");		return -EINVAL;	}	if (copy_from_user(&aen, (void __user *)arg, sizeof(aen)))		return -EFAULT;	instance = megasas_lookup_instance(aen.host_no);	if (!instance)		return -ENODEV;	down(&instance->aen_mutex);	error = megasas_register_aen(instance, aen.seq_num,				     aen.class_locale_word);	up(&instance->aen_mutex);	return error;}/** * megasas_mgmt_ioctl -	char node ioctl entry point */static longmegasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	switch (cmd) {	case MEGASAS_IOC_FIRMWARE:		return megasas_mgmt_ioctl_fw(file, arg);	case MEGASAS_IOC_GET_AEN:		return megasas_mgmt_ioctl_aen(file, arg);	}	return -ENOTTY;}#ifdef CONFIG_COMPATstatic int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg){	struct compat_megasas_iocpacket __user *cioc =	    (struct compat_megasas_iocpacket __user *)arg;	struct megasas_iocpacket __user *ioc =	    compat_alloc_user_space(sizeof(struct megasas_iocpacket));	int i;	int error = 0;	clear_user(ioc, sizeof(*ioc));	if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||	    copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||	    copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) ||	    copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) ||	    copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) ||	    copy_in_user(&ioc->sge_count, &cioc->sge_count, 

⌨️ 快捷键说明

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