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

📄 cpqarray.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (!got_from_pool) {		pci_free_consistent(h->pci_dev, sizeof(cmdlist_t), c,			c->busaddr);	} else {		i = c - h->cmd_pool;		clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));		h->nr_frees++;	}}/***********************************************************************    name:        sendcmd    Send a command to an IDA using the memory mapped FIFO interface    and wait for it to complete.      This routine should only be called at init time.***********************************************************************/static int sendcmd(	__u8	cmd,	int	ctlr,	void	*buff,	size_t	size,	unsigned int blk,	unsigned int blkcnt,	unsigned int log_unit ){	cmdlist_t *c;	int complete;	unsigned long temp;	unsigned long i;	ctlr_info_t *info_p = hba[ctlr];	c = cmd_alloc(info_p, 1);	if(!c)		return IO_ERROR;	c->ctlr = ctlr;	c->hdr.unit = log_unit;	c->hdr.prio = 0;	c->hdr.size = sizeof(rblk_t) >> 2;	c->size += sizeof(rblk_t);	/* The request information. */	c->req.hdr.next = 0;	c->req.hdr.rcode = 0;	c->req.bp = 0;	c->req.hdr.sg_cnt = 1;	c->req.hdr.reserved = 0;		if (size == 0)		c->req.sg[0].size = 512;	else		c->req.sg[0].size = size;	c->req.hdr.blk = blk;	c->req.hdr.blk_cnt = blkcnt;	c->req.hdr.cmd = (unsigned char) cmd;	c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, 		buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);	/*	 * Disable interrupt	 */	info_p->access.set_intr_mask(info_p, 0);	/* Make sure there is room in the command FIFO */	/* Actually it should be completely empty at this time. */	for (i = 200000; i > 0; i--) {		temp = info_p->access.fifo_full(info_p);		if (temp != 0) {			break;		}		udelay(10);DBG(		printk(KERN_WARNING "cpqarray ida%d: idaSendPciCmd FIFO full,"			" waiting!\n", ctlr););	} 	/*	 * Send the cmd	 */	info_p->access.submit_command(info_p, c);	complete = pollcomplete(ctlr);		pci_unmap_single(info_p->pci_dev, (dma_addr_t) c->req.sg[0].addr, 		c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);	if (complete != 1) {		if (complete != c->busaddr) {			printk( KERN_WARNING			"cpqarray ida%d: idaSendPciCmd "		      "Invalid command list address returned! (%08lx)\n",				ctlr, (unsigned long)complete);			cmd_free(info_p, c, 1);			return (IO_ERROR);		}	} else {		printk( KERN_WARNING			"cpqarray ida%d: idaSendPciCmd Timeout out, "			"No command list address returned!\n",			ctlr);		cmd_free(info_p, c, 1);		return (IO_ERROR);	}	if (c->req.hdr.rcode & 0x00FE) {		if (!(c->req.hdr.rcode & BIG_PROBLEM)) {			printk( KERN_WARNING			"cpqarray ida%d: idaSendPciCmd, error: "				"Controller failed at init time "				"cmd: 0x%x, return code = 0x%x\n",				ctlr, c->req.hdr.cmd, c->req.hdr.rcode);			cmd_free(info_p, c, 1);			return (IO_ERROR);		}	}	cmd_free(info_p, c, 1);	return (IO_OK);}/* * 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;	int i;	unsigned long flags;	spin_lock_irqsave(IDA_LOCK(ctlr), flags);	if (host->usage_count > 1) {		spin_unlock_irqrestore(IDA_LOCK(ctlr), flags);		printk(KERN_WARNING "cpqarray: Device busy for volume"			" revalidation (usage=%d)\n", host->usage_count);		return -EBUSY;	}	host->usage_count++;	spin_unlock_irqrestore(IDA_LOCK(ctlr), flags);	/*	 * Set the partition and block size structures for all volumes	 * on this controller to zero.  We will reread all of this data	 */	set_capacity(ida_gendisk[ctlr][0], 0);	for (i = 1; i < NWD; i++) {		struct gendisk *disk = ida_gendisk[ctlr][i];		if (disk->flags & GENHD_FL_UP)			del_gendisk(disk);	}	memset(host->drv, 0, sizeof(drv_info_t)*NWD);	/*	 * 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, 0);	getgeometry(ctlr);	host->access.set_intr_mask(host, FIFO_NOT_EMPTY);	for(i=0; i<NWD; i++) {		struct gendisk *disk = ida_gendisk[ctlr][i];		drv_info_t *drv = &host->drv[i];		if (i && !drv->nr_blks)			continue;		blk_queue_hardsect_size(host->queue, drv->blk_size);		set_capacity(disk, drv->nr_blks);		disk->queue = host->queue;		disk->private_data = drv;		if (i)			add_disk(disk);	}	host->usage_count--;	return 0;}static int ida_revalidate(struct gendisk *disk){	drv_info_t *drv = disk->private_data;	set_capacity(disk, drv->nr_blks);	return 0;}/********************************************************************    name: pollcomplete    Wait polling for a command to complete.    The memory mapped FIFO is polled for the completion.    Used only at init time, interrupts disabled. ********************************************************************/static int pollcomplete(int ctlr){	int done;	int i;	/* Wait (up to 2 seconds) for a command to complete */	for (i = 200000; i > 0; i--) {		done = hba[ctlr]->access.command_completed(hba[ctlr]);		if (done == 0) {			udelay(10);	/* a short fixed delay */		} else			return (done);	}	/* Invalid address to tell caller we ran out of time */	return 1;}/*****************************************************************    start_fwbk    Starts controller firmwares background processing.     Currently only the Integrated Raid controller needs this done.    If the PCI mem address registers are written to after this, 	 data corruption may occur*****************************************************************/static void start_fwbk(int ctlr){		id_ctlr_t *id_ctlr_buf; 	int ret_code;	if(	(hba[ctlr]->board_id != 0x40400E11)		&& (hba[ctlr]->board_id != 0x40480E11) )	/* Not a Integrated Raid, so there is nothing for us to do */		return;	printk(KERN_DEBUG "cpqarray: Starting firmware's background"		" processing\n");	/* Command does not return anything, but idasend command needs a 		buffer */	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);	if(id_ctlr_buf==NULL)	{		printk(KERN_WARNING "cpqarray: Out of memory. "			"Unable to start background processing.\n");		return;	}			ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, 		id_ctlr_buf, 0, 0, 0, 0);	if(ret_code != IO_OK)		printk(KERN_WARNING "cpqarray: Unable to start"			" background processing\n");	kfree(id_ctlr_buf);}/*****************************************************************    getgeometry    Get ida logical volume geometry from the controller     This is a large bit of code which once existed in two flavors,    It is used only at init time.*****************************************************************/static void getgeometry(int ctlr){					id_log_drv_t *id_ldrive;	id_ctlr_t *id_ctlr_buf;	sense_log_drv_stat_t *id_lstatus_buf;	config_t *sense_config_buf;	unsigned int log_unit, log_index;	int ret_code, size;	drv_info_t *drv;	ctlr_info_t *info_p = hba[ctlr];	int i;	info_p->log_drv_map = 0;			id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);	if(id_ldrive == NULL)	{		printk( KERN_ERR "cpqarray:  out of memory.\n");		return;	}	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);	if(id_ctlr_buf == NULL)	{		kfree(id_ldrive);		printk( KERN_ERR "cpqarray:  out of memory.\n");		return;	}	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);	if(id_lstatus_buf == NULL)	{		kfree(id_ctlr_buf);		kfree(id_ldrive);		printk( KERN_ERR "cpqarray:  out of memory.\n");		return;	}	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);	if(sense_config_buf == NULL)	{		kfree(id_lstatus_buf);		kfree(id_ctlr_buf);		kfree(id_ldrive);		printk( KERN_ERR "cpqarray:  out of memory.\n");		return;	}	memset(id_ldrive, 0, sizeof(id_log_drv_t));	memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));	memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));	memset(sense_config_buf, 0, sizeof(config_t));	info_p->phys_drives = 0;	info_p->log_drv_map = 0;	info_p->drv_assign_map = 0;	info_p->drv_spare_map = 0;	info_p->mp_failed_drv_map = 0;	/* only initialized here */	/* Get controllers info for this logical drive */	ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0);	if (ret_code == IO_ERROR) {		/*		 * If can't get controller info, set the logical drive map to 0,		 * so the idastubopen will fail on all logical drives		 * on the controller.		 */		 /* Free all the buffers and return */ 		printk(KERN_ERR "cpqarray: error sending ID controller\n");		kfree(sense_config_buf);                kfree(id_lstatus_buf);                kfree(id_ctlr_buf);                kfree(id_ldrive);                return;        }	info_p->log_drives = id_ctlr_buf->nr_drvs;	for(i=0;i<4;i++)		info_p->firm_rev[i] = id_ctlr_buf->firm_rev[i];	info_p->ctlr_sig = id_ctlr_buf->cfg_sig;	printk(" (%s)\n", info_p->product_name);	/*	 * Initialize logical drive map to zero	 */	log_index = 0;	/*	 * Get drive geometry for all logical drives	 */	if (id_ctlr_buf->nr_drvs > 16)		printk(KERN_WARNING "cpqarray ida%d:  This driver supports "			"16 logical drives per controller.\n.  "			" Additional drives will not be "			"detected\n", ctlr);	for (log_unit = 0;	     (log_index < id_ctlr_buf->nr_drvs)	     && (log_unit < NWD);	     log_unit++) {		struct gendisk *disk = ida_gendisk[ctlr][log_unit];		size = sizeof(sense_log_drv_stat_t);		/*		   Send "Identify logical drive status" cmd		 */		ret_code = sendcmd(SENSE_LOG_DRV_STAT,			     ctlr, id_lstatus_buf, size, 0, 0, log_unit);		if (ret_code == IO_ERROR) {			/*			   If can't get logical drive status, set			   the logical drive map to 0, so the			   idastubopen will fail for all logical drives			   on the controller. 			 */			info_p->log_drv_map = 0;				printk( KERN_WARNING			     "cpqarray ida%d: idaGetGeometry - Controller"				" failed to report status of logical drive %d\n"			 "Access to this controller has been disabled\n",				ctlr, log_unit);			/* Free all the buffers and return */                	kfree(sense_config_buf);                	kfree(id_lstatus_buf);                	kfree(id_ctlr_buf);                	kfree(id_ldrive);                	return;		}		/*		   Make sure the logical drive is configured		 */		if (id_lstatus_buf->status != LOG_NOT_CONF) {			ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive,			       sizeof(id_log_drv_t), 0, 0, log_unit);			/*			   If error, the bit for this			   logical drive won't be set and			   idastubopen will return error. 			 */			if (ret_code != IO_ERROR) {				drv = &info_p->drv[log_unit];				drv->blk_size = id_ldrive->blk_size;				drv->nr_blks = id_ldrive->nr_blks;				drv->cylinders = id_ldrive->drv.cyl;				drv->heads = id_ldrive->drv.heads;				drv->sectors = id_ldrive->drv.sect_per_track;				info_p->log_drv_map |=	(1 << log_unit);	printk(KERN_INFO "cpqarray ida/c%dd%d: blksz=%d nr_blks=%d\n",		ctlr, log_unit, drv->blk_size, drv->nr_blks);				ret_code = sendcmd(SENSE_CONFIG,						  ctlr, sense_config_buf,				 sizeof(config_t), 0, 0, log_unit);				if (ret_code == IO_ERROR) {					info_p->log_drv_map = 0;					/* Free all the buffers and return */                			printk(KERN_ERR "cpqarray: error sending sense config\n");                			kfree(sense_config_buf);                			kfree(id_lstatus_buf);                			kfree(id_ctlr_buf);                			kfree(id_ldrive);                			return;				}				sprintf(disk->devfs_name, "ida/c%dd%d", ctlr, log_unit);				info_p->phys_drives =				    sense_config_buf->ctlr_phys_drv;				info_p->drv_assign_map				    |= sense_config_buf->drv_asgn_map;				info_p->drv_assign_map				    |= sense_config_buf->spare_asgn_map;				info_p->drv_spare_map				    |= sense_config_buf->spare_asgn_map;			}	/* end of if no error on id_ldrive */			log_index = log_index + 1;		}		/* end of if logical drive configured */	}			/* end of for log_unit */	kfree(sense_config_buf);  	kfree(id_ldrive);  	kfree(id_lstatus_buf);	kfree(id_ctlr_buf);	return;}static void __exit cpqarray_exit(void){	int i;	pci_unregister_driver(&cpqarray_pci_driver);	/* Double check that all controller entries have been removed */	for(i=0; i<MAX_CTLR; i++) {		if (hba[i] != NULL) {			printk(KERN_WARNING "cpqarray: Removing EISA "					"controller %d\n", i);			cpqarray_remove_one_eisa(i);		}	}	devfs_remove("ida");	remove_proc_entry("cpqarray", proc_root_driver);}module_init(cpqarray_init)module_exit(cpqarray_exit)

⌨️ 快捷键说明

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