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

📄 cciss.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		} else{ /* reading number of logical volumes failed */			printk(KERN_WARNING "cciss: report logical volume"				" command failed\n");			listlength = 0;			goto freeret;		}		num_luns = listlength / 8;	/* 8 bytes per entry */		if (num_luns > CISS_MAX_LUN){			num_luns = CISS_MAX_LUN;			printk(KERN_WARNING "cciss: more luns configured"				" on controller than can be handled by"				" this driver.\n");		}		/* Compare controller drive array to drivers drive array.	 	* Check for updates in the drive information and any new drives	 	* on the controller.	 	*/		for (i=0; i < num_luns; i++){			int j;			drv_found = 0;	  		lunid = (0xff &				(unsigned int)(ld_buff->LUN[i][3])) << 24;        		lunid |= (0xff &				(unsigned int)(ld_buff->LUN[i][2])) << 16;        		lunid |= (0xff &				(unsigned int)(ld_buff->LUN[i][1])) << 8;        		lunid |= 0xff &				(unsigned int)(ld_buff->LUN[i][0]);			/* Find if the LUN is already in the drive array			 * of the controller.  If so then update its info			 * if not is use.  If it does not exist then find			 * the first free index and add it.			*/			for (j=0; j <= h->highest_lun; j++){				if (h->drv[j].LunID == lunid){					drv_index = j;					drv_found = 1;				}			}			/* check if the drive was found already in the array */			if (!drv_found){				drv_index = cciss_find_free_drive_index(ctlr);				if (drv_index == -1)					goto freeret;			}			h->drv[drv_index].LunID = lunid;			cciss_update_drive_info(ctlr, drv_index);		} /* end for */	} /* end else */freeret:	kfree(ld_buff);	h->busy_configuring = 0;	/* We return -1 here to tell the ACU that we have registered/updated	 * all of the drives that we can and to keep it from calling us	 * additional times.	*/	return -1;mem_msg:	printk(KERN_ERR "cciss: out of memory\n");	goto freeret;}/* This function will deregister the disk and it's queue from the * kernel.  It must be called with the controller lock held and the * drv structures busy_configuring flag set.  It's parameters are: * * disk = This is the disk to be deregistered * drv  = This is the drive_info_struct associated with the disk to be *        deregistered.  It contains information about the disk used *        by the driver. * clear_all = This flag determines whether or not the disk information *             is going to be completely cleared out and the highest_lun *             reset.  Sometimes we want to clear out information about *             the disk in preperation for re-adding it.  In this case *             the highest_lun should be left unchanged and the LunID *             should not be cleared.*/static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,			   int clear_all){	ctlr_info_t *h = get_host(disk);	if (!capable(CAP_SYS_RAWIO))		return -EPERM;	/* make sure logical volume is NOT is use */	if(clear_all || (h->gendisk[0] == disk)) {	if (drv->usage_count > 1)                return -EBUSY;	}        else        	if( drv->usage_count > 0 )                	return -EBUSY;	/* invalidate the devices and deregister the disk.  If it is disk	 * zero do not deregister it but just zero out it's values.  This	 * allows us to delete disk zero but keep the controller registered.	*/	if (h->gendisk[0] != disk){		if (disk->flags & GENHD_FL_UP){			blk_cleanup_queue(disk->queue);		del_gendisk(disk);			drv->queue = NULL;		}	}	--h->num_luns;	/* zero out the disk size info */	drv->nr_blocks = 0;	drv->block_size = 0;	drv->heads = 0;	drv->sectors = 0;	drv->cylinders = 0;	drv->raid_level = -1;	/* This can be used as a flag variable to				 * indicate that this element of the drive				 * array is free.				*/	if (clear_all){	/* 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].heads)				newhighest = i;		}		h->highest_lun = newhighest;	}	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 */ 		switch(c->err_info->CommandStatus)		{			case CMD_TARGET_STATUS:				printk(KERN_WARNING "cciss: cmd %p has "					" completed with errors\n", c);				if( c->err_info->ScsiStatus)                		{                    			printk(KERN_WARNING "cciss: cmd %p "					"has SCSI Status = %x\n",                        			c,  						c->err_info->ScsiStatus);                		}			break;			case CMD_DATA_UNDERRUN:			case CMD_DATA_OVERRUN:			/* expected for inquire and report lun commands */			break;			case CMD_INVALID:				printk(KERN_WARNING "cciss: Cmd %p is "					"reported invalid\n", c);				return_status = IO_ERROR;			break;			case CMD_PROTOCOL_ERR:                                printk(KERN_WARNING "cciss: cmd %p has "					"protocol error \n", c);                                return_status = IO_ERROR;                        break;case CMD_HARDWARE_ERR:                                printk(KERN_WARNING "cciss: cmd %p had "                                         " hardware error\n", c);                                return_status = IO_ERROR;                        break;			case CMD_CONNECTION_LOST:				printk(KERN_WARNING "cciss: cmd %p had "					"connection lost\n", c);				return_status = IO_ERROR;			break;			case CMD_ABORTED:				printk(KERN_WARNING "cciss: cmd %p was "					"aborted\n", c);				return_status = IO_ERROR;			break;			case CMD_ABORT_FAILED:				printk(KERN_WARNING "cciss: cmd %p reports "					"abort failed\n", c);				return_status = IO_ERROR;			break;			case CMD_UNSOLICITED_ABORT:				printk(KERN_WARNING 					"cciss%d: unsolicited abort %p\n",					ctlr, c);				if (c->retry_count < MAX_CMD_RETRIES) {					printk(KERN_WARNING 						"cciss%d: retrying %p\n", 						ctlr, c);					c->retry_count++;					/* erase the old error information */					memset(c->err_info, 0,						sizeof(ErrorInfo_struct));					return_status = IO_OK;					INIT_COMPLETION(wait);					goto resend_cmd2;				}				return_status = IO_ERROR;			break;			default:				printk(KERN_WARNING "cciss: cmd %p returned "					"unknown status %x\n", c, 						c->err_info->CommandStatus); 				return_status = IO_ERROR;		}	}		/* unlock the buffers from DMA */	buff_dma_handle.val32.lower = c->SG[0].Addr.lower;	buff_dma_handle.val32.upper = c->SG[0].Addr.upper;	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,			c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);	cmd_free(h, c, 0);        return(return_status);}static void cciss_geometry_inquiry(int ctlr, int logvol,			int withirq, unsigned int total_size,			unsigned int block_size, InquiryData_struct *inq_buff,			drive_info_struct *drv){	int return_code;	memset(inq_buff, 0, sizeof(InquiryData_struct));	if (withirq)		return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,			inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD);	else		return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,			sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD);	if (return_code == IO_OK) {		if(inq_buff->data_byte[8] == 0xFF) {			printk(KERN_WARNING				"cciss: reading geometry failed, volume "				"does not support reading geometry\n");			drv->block_size = block_size;			drv->nr_blocks = total_size;			drv->heads = 255;			drv->sectors = 32; // Sectors per track			drv->cylinders = total_size / 255 / 32;		} else {			unsigned int t;			drv->block_size = block_size;			drv->nr_blocks = total_size;			drv->heads = inq_buff->data_byte[6];			drv->sectors = inq_buff->data_byte[7];			drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8;			drv->cylinders += inq_buff->data_byte[5];			drv->raid_level = inq_buff->data_byte[8];			t = drv->heads * drv->sectors;			if (t > 1) {				drv->cylinders = total_size/t;			}		}	} else { /* Get geometry failed */		printk(KERN_WARNING "cciss: reading geometry failed\n");	}	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",		drv->heads, drv->sectors, drv->cylinders);}static voidcciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,		int withirq, unsigned int *total_size, unsigned int *block_size){	int return_code;	memset(buf, 0, sizeof(*buf));	if (withirq)		return_code = sendcmd_withirq(CCISS_READ_CAPACITY,			ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD);	else		return_code = sendcmd(CCISS_READ_CAPACITY,			ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);	if (return_code == IO_OK) {		*total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1;		*block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0]));	} else { /* read capacity command failed */		printk(KERN_WARNING "cciss: read capacity failed\n");		*total_size = 0;		*block_size = BLOCK_SIZE;

⌨️ 快捷键说明

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