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

📄 dpt_i2o.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	adpt_hba* p2;	struct i2o_device* d;	struct i2o_device* next;	int i;	int j;	struct adpt_device* pDev;	struct adpt_device* pNext;	down(&adpt_configuration_lock);	// scsi_unregister calls our adpt_release which	// does a quiese	if(pHba->host){		free_irq(pHba->host->irq, pHba);	}	for(i=0;i<DPTI_MAX_HBA;i++) {		if(hbas[i]==pHba) {			hbas[i] = NULL;		}	}	p2 = NULL;	for( p1 = hba_chain; p1; p2 = p1,p1=p1->next){		if(p1 == pHba) {			if(p2) {				p2->next = p1->next;			} else {				hba_chain = p1->next;			}			break;		}	}	hba_count--;	up(&adpt_configuration_lock);	iounmap((void*)pHba->base_addr_virt);	if(pHba->msg_addr_virt != pHba->base_addr_virt){		iounmap((void*)pHba->msg_addr_virt);	}	if(pHba->hrt) {		kfree(pHba->hrt);	}	if(pHba->lct){		kfree(pHba->lct);	}	if(pHba->status_block) {		kfree(pHba->status_block);	}	if(pHba->reply_pool){		kfree(pHba->reply_pool);	}	for(d = pHba->devices; d ; d = next){		next = d->next;		kfree(d);	}	for(i = 0 ; i < pHba->top_scsi_channel ; i++){		for(j = 0; j < MAX_ID; j++){			if(pHba->channel[i].device[j] != NULL){				for(pDev = pHba->channel[i].device[j]; pDev; pDev = pNext){					pNext = pDev->next_lun;					kfree(pDev);				}			}		}	}	kfree(pHba);	if(hba_count <= 0){		unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);   	}}static int adpt_init(void){	int i;	printk(KERN_INFO"Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");	for (i = 0; i < DPTI_MAX_HBA; i++) {		hbas[i] = NULL;	}#ifdef REBOOT_NOTIFIER	register_reboot_notifier(&adpt_reboot_notifier);#endif	return 0;}static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun){	struct adpt_device* d;	if(chan < 0 || chan >= MAX_CHANNEL)		return NULL;		if( pHba->channel[chan].device == NULL){		printk(KERN_DEBUG"Adaptec I2O RAID: Trying to find device before they are allocated\n");		return NULL;	}	d = pHba->channel[chan].device[id];	if(!d || d->tid == 0) {		return NULL;	}	/* If it is the only lun at that address then this should match*/	if(d->scsi_lun == lun){		return d;	}	/* else we need to look through all the luns */	for(d=d->next_lun ; d ; d = d->next_lun){		if(d->scsi_lun == lun){			return d;		}	}	return NULL;}static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout){	// I used my own version of the WAIT_QUEUE_HEAD	// to handle some version differences	// When embedded in the kernel this could go back to the vanilla one	ADPT_DECLARE_WAIT_QUEUE_HEAD(adpt_wq_i2o_post);	int status = 0;	ulong flags = 0;	struct adpt_i2o_post_wait_data *p1, *p2;	struct adpt_i2o_post_wait_data *wait_data =		kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL);	adpt_wait_queue_t wait;	if(!wait_data){		return -ENOMEM;	}	/*	 * The spin locking is needed to keep anyone from playing	 * with the queue pointers and id while we do the same	 */	spin_lock_irqsave(&adpt_post_wait_lock, flags);       // TODO we need a MORE unique way of getting ids       // to support async LCT get	wait_data->next = adpt_post_wait_queue;	adpt_post_wait_queue = wait_data;	adpt_post_wait_id = (++adpt_post_wait_id & 0x7fff);	wait_data->id =  adpt_post_wait_id;	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);	wait_data->wq = &adpt_wq_i2o_post;	wait_data->status = -ETIMEDOUT;	// this code is taken from kernel/sched.c:interruptible_sleep_on_timeout	wait.task = current;	init_waitqueue_entry(&wait, current);	wq_write_lock_irqsave(&adpt_wq_i2o_post.lock,flags);	__add_wait_queue(&adpt_wq_i2o_post, &wait);	wq_write_unlock(&adpt_wq_i2o_post.lock);	msg[2] |= 0x80000000 | ((u32)wait_data->id);	timeout *= HZ;	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){		if(!timeout){			set_current_state(TASK_INTERRUPTIBLE);			spin_unlock_irq(&io_request_lock);			schedule();			spin_lock_irq(&io_request_lock);		} else {			set_current_state(TASK_INTERRUPTIBLE);			spin_unlock_irq(&io_request_lock);			schedule_timeout(timeout*HZ);			spin_lock_irq(&io_request_lock);		}	}	wq_write_lock_irq(&adpt_wq_i2o_post.lock);	__remove_wait_queue(&adpt_wq_i2o_post, &wait);	wq_write_unlock_irqrestore(&adpt_wq_i2o_post.lock,flags);	if(status == -ETIMEDOUT){		printk(KERN_INFO"dpti%d: POST WAIT TIMEOUT\n",pHba->unit);		// We will have to free the wait_data memory during shutdown		return status;	}	/* Remove the entry from the queue.  */	p2 = NULL;	spin_lock_irqsave(&adpt_post_wait_lock, flags);	for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p1->next) {		if(p1 == wait_data) {			if(p1->status == I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION ) {				status = -EOPNOTSUPP;			}			if(p2) {				p2->next = p1->next;			} else {				adpt_post_wait_queue = p1->next;			}			break;		}	}	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);	kfree(wait_data);	return status;}static s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len){	u32 m = EMPTY_QUEUE;	u32 *msg;	ulong timeout = jiffies + 30*HZ;	do {		rmb();		m = readl(pHba->post_port);		if (m != EMPTY_QUEUE) {			break;		}		if(time_after(jiffies,timeout)){			printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit);			return -ETIMEDOUT;		}	} while(m == EMPTY_QUEUE);			msg = (u32*) (pHba->msg_addr_virt + m);	memcpy_toio(msg, data, len);	wmb();	//post message	writel(m, pHba->post_port);	wmb();	return 0;}static void adpt_i2o_post_wait_complete(u32 context, int status){	struct adpt_i2o_post_wait_data *p1 = NULL;	/*	 * We need to search through the adpt_post_wait	 * queue to see if the given message is still	 * outstanding.  If not, it means that the IOP	 * took longer to respond to the message than we	 * had allowed and timer has already expired.	 * Not much we can do about that except log	 * it for debug purposes, increase timeout, and recompile	 *	 * Lock needed to keep anyone from moving queue pointers	 * around while we're looking through them.	 */	context &= 0x7fff;	spin_lock(&adpt_post_wait_lock);	for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) {		if(p1->id == context) {			p1->status = status;			spin_unlock(&adpt_post_wait_lock);			wake_up_interruptible(p1->wq);			return;		}	}	spin_unlock(&adpt_post_wait_lock);        // If this happens we loose commands that probably really completed	printk(KERN_DEBUG"dpti: Could Not find task %d in wait queue\n",context);	printk(KERN_DEBUG"      Tasks in wait queue:\n");	for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) {		printk(KERN_DEBUG"           %d\n",p1->id);	}	return;}static s32 adpt_i2o_reset_hba(adpt_hba* pHba)			{	u32 msg[8];	u8* status;	u32 m = EMPTY_QUEUE ;	ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);	if(pHba->initialized  == FALSE) {	// First time reset should be quick		timeout = jiffies + (25*HZ);	} else {		adpt_i2o_quiesce_hba(pHba);	}	do {		rmb();		m = readl(pHba->post_port);		if (m != EMPTY_QUEUE) {			break;		}		if(time_after(jiffies,timeout)){			printk(KERN_WARNING"Timeout waiting for message!\n");			return -ETIMEDOUT;		}	} while (m == EMPTY_QUEUE);	status = (u8*)kmalloc(4, GFP_KERNEL|ADDR32);	if(status == NULL) {		adpt_send_nop(pHba, m);		printk(KERN_ERR"IOP reset failed - no free memory.\n");		return -ENOMEM;	}	memset(status,0,4);	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;	msg[2]=0;	msg[3]=0;	msg[4]=0;	msg[5]=0;	msg[6]=virt_to_bus(status);	msg[7]=0;     	memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));	wmb();	writel(m, pHba->post_port);	wmb();	while(*status == 0){		if(time_after(jiffies,timeout)){			printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);			kfree(status);			return -ETIMEDOUT;		}		rmb();	}	if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) {		PDEBUG("%s: Reset in progress...\n", pHba->name);		// Here we wait for message frame to become available		// indicated that reset has finished		do {			rmb();			m = readl(pHba->post_port);			if (m != EMPTY_QUEUE) {				break;			}			if(time_after(jiffies,timeout)){				printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);				return -ETIMEDOUT;			}		} while (m == EMPTY_QUEUE);		// Flush the offset		adpt_send_nop(pHba, m);	}	adpt_i2o_status_get(pHba);	if(*status == 0x02 ||			pHba->status_block->iop_state != ADAPTER_STATE_RESET) {		printk(KERN_WARNING"%s: Reset reject, trying to clear\n",				pHba->name);	} else {		PDEBUG("%s: Reset completed.\n", pHba->name);	}	kfree(status);#ifdef UARTDELAY	// This delay is to allow someone attached to the card through the debug UART to 	// set up the dump levels that they want before the rest of the initialization sequence	adpt_delay(20000);#endif	return 0;}static int adpt_i2o_parse_lct(adpt_hba* pHba){	int i;	int max;	int tid;	struct i2o_device *d;	i2o_lct *lct = pHba->lct;	u8 bus_no = 0;	s16 scsi_id;	s16 scsi_lun;	u32 buf[10]; // larger than 7, or 8 ...	struct adpt_device* pDev; 		if (lct == NULL) {		printk(KERN_ERR "%s: LCT is empty???\n",pHba->name);		return -1;	}		max = lct->table_size;		max -= 3;	max /= 9;	for(i=0;i<max;i++) {		if( lct->lct_entry[i].user_tid != 0xfff){			/*			 * If we have hidden devices, we need to inform the upper layers about			 * the possible maximum id reference to handle device access when			 * an array is disassembled. This code has no other purpose but to			 * allow us future access to devices that are currently hidden			 * behind arrays, hotspares or have not been configured (JBOD mode).			 */			if( lct->lct_entry[i].class_id != I2O_CLASS_RANDOM_BLOCK_STORAGE &&			    lct->lct_entry[i].class_id != I2O_CLASS_SCSI_PERIPHERAL &&			    lct->lct_entry[i].class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){			    	continue;			}			tid = lct->lct_entry[i].tid;			// I2O_DPT_DEVICE_INFO_GROUP_NO;			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) {				continue;			}			bus_no = buf[0]>>16;			scsi_id = buf[1];			scsi_lun = (buf[2]>>8 )&0xff;			if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it				printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no);				continue;			}			if(scsi_id > MAX_ID){				printk(KERN_WARNING"%s: SCSI ID %d out of range \n", pHba->name, bus_no);				continue;			}			if(bus_no > pHba->top_scsi_channel){				pHba->top_scsi_channel = bus_no;			}			if(scsi_id > pHba->top_scsi_id){				pHba->top_scsi_id = scsi_id;			}			if(scsi_lun > pHba->top_scsi_lun){				pHba->top_scsi_lun = scsi_lun;			}			continue;		}		d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);		if(d==NULL)		{			printk(KERN_CRIT"%s: Out of memory for I2O device data.\n",pHba->name);			return -ENOMEM;		}				d->controller = (void*)pHba;		d->next = NULL;		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));		d->flags = 0;		tid = d->lct_data.tid;		adpt_i2o_report_hba_unit(pHba, d);		adpt_i2o_install_device(pHba, d);	}	bus_no = 0;	for(d = pHba->devices; d ; d = d->next) {		if(d->lct_data.class_id  == I2O_CLASS_BUS_ADAPTER_PORT ||		   d->lct_data.class_id  == I2O_CLASS_FIBRE_CHANNEL_PORT){			tid = d->lct_data.tid;			// TODO get the bus_no from hrt-but for now they are in order			//bus_no = 			if(bus_no > pHba->top_scsi_channel){				pHba->top_scsi_channel = bus_no;			}			pHba->channel[bus_no].type = d->lct_data.class_id;			pHba->channel[bus_no].tid = tid;			if(adpt_i2o_query_scalar(pHba, tid, 0x0200, -1, buf, 28)>=0)			{				pHba->channel[bus_no].scsi_id = buf[1];				PDEBUG("Bus %d - SCSI ID %d.\n", bus_no, buf[1]);			}			// TODO remove - this is just until we get from hrt			bus_no++;			if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it				printk(KERN_WARNING"%s: Channel number %d out of range - LCT\n", pHba->name, bus_no);				break;			}		}	}	// Setup adpt_device table	for(d = pHba->devices; d ; d = d->next) {		if(d->lct_data.class_id  == I2O_CLASS_RANDOM_BLOCK_STORAGE ||		   d->lct_data.class_id  == I2O_CLASS_SCSI_PERIPHERAL ||		   d->lct_data.class_id  == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){			tid = d->lct_data.tid;			scsi_id = -1;			// I2O_DPT_DEVICE_INFO_GROUP_NO;			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)>=0) {				bus_no = buf[0]>>16;				scsi_id = buf[1];				scsi_lun = (buf[2]>>8 )&0xff;				if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it					continue;				}				if(scsi_id > MAX_ID){					continue;				}				if( pHba->channel[bus_no].device[scsi_id] == NULL){					pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);					if(pDev == NULL) {

⌨️ 快捷键说明

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