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

📄 megaraid.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	switch (mbox->m_out.cmd) {	case MEGA_MBOXCMD_LREAD64:	case MEGA_MBOXCMD_LWRITE64:	case MEGA_MBOXCMD_PASSTHRU64:	case MEGA_MBOXCMD_EXTPTHRU:		mbox64->xfer_segment_lo = mbox->m_out.xferaddr;		mbox64->xfer_segment_hi = 0;		mbox->m_out.xferaddr = 0xFFFFFFFF;		break;	default:		mbox64->xfer_segment_lo = 0;		mbox64->xfer_segment_hi = 0;	}	/*	 * post the command	 */	scb->state |= SCB_ISSUED;	if( likely(adapter->flag & BOARD_MEMMAP) ) {		mbox->m_in.poll = 0;		mbox->m_in.ack = 0;		WRINDOOR(adapter, adapter->mbox_dma | 0x1);	}	else {		irq_enable(adapter);		issue_command(adapter);	}	return 0;}/* * Wait until the controller's mailbox is available */static inline intmega_busywait_mbox (adapter_t *adapter){	if (adapter->mbox->m_in.busy)		return __mega_busywait_mbox(adapter);	return 0;}/** * issue_scb_block() * @adapter - pointer to our soft state * @raw_mbox - the mailbox * * Issue a scb in synchronous and non-interrupt mode */static intissue_scb_block(adapter_t *adapter, u_char *raw_mbox){	volatile mbox64_t *mbox64 = adapter->mbox64;	volatile mbox_t *mbox = adapter->mbox;	u8	byte;	/* Wait until mailbox is free */	if(mega_busywait_mbox (adapter))		goto bug_blocked_mailbox;	/* Copy mailbox data into host structure */	memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out));	mbox->m_out.cmdid = 0xFE;	mbox->m_in.busy = 1;	switch (raw_mbox[0]) {	case MEGA_MBOXCMD_LREAD64:	case MEGA_MBOXCMD_LWRITE64:	case MEGA_MBOXCMD_PASSTHRU64:	case MEGA_MBOXCMD_EXTPTHRU:		mbox64->xfer_segment_lo = mbox->m_out.xferaddr;		mbox64->xfer_segment_hi = 0;		mbox->m_out.xferaddr = 0xFFFFFFFF;		break;	default:		mbox64->xfer_segment_lo = 0;		mbox64->xfer_segment_hi = 0;	}	if( likely(adapter->flag & BOARD_MEMMAP) ) {		mbox->m_in.poll = 0;		mbox->m_in.ack = 0;		mbox->m_in.numstatus = 0xFF;		mbox->m_in.status = 0xFF;		WRINDOOR(adapter, adapter->mbox_dma | 0x1);		while((volatile u8)mbox->m_in.numstatus == 0xFF)			cpu_relax();		mbox->m_in.numstatus = 0xFF;		while( (volatile u8)mbox->m_in.poll != 0x77 )			cpu_relax();		mbox->m_in.poll = 0;		mbox->m_in.ack = 0x77;		WRINDOOR(adapter, adapter->mbox_dma | 0x2);		while(RDINDOOR(adapter) & 0x2)			cpu_relax();	}	else {		irq_disable(adapter);		issue_command(adapter);		while (!((byte = irq_state(adapter)) & INTR_VALID))			cpu_relax();		set_irq_state(adapter, byte);		irq_enable(adapter);		irq_ack(adapter);	}	return mbox->m_in.status;bug_blocked_mailbox:	printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n");	udelay (1000);	return -1;}/** * megaraid_isr_iomapped() * @irq - irq * @devp - pointer to our soft state * * Interrupt service routine for io-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */static irqreturn_tmegaraid_isr_iomapped(int irq, void *devp){	adapter_t	*adapter = devp;	unsigned long	flags;	u8	status;	u8	nstatus;	u8	completed[MAX_FIRMWARE_STATUS];	u8	byte;	int	handled = 0;	/*	 * loop till F/W has more commands for us to complete.	 */	spin_lock_irqsave(&adapter->lock, flags);	do {		/* Check if a valid interrupt is pending */		byte = irq_state(adapter);		if( (byte & VALID_INTR_BYTE) == 0 ) {			/*			 * No more pending commands			 */			goto out_unlock;		}		set_irq_state(adapter, byte);		while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus)				== 0xFF)			cpu_relax();		adapter->mbox->m_in.numstatus = 0xFF;		status = adapter->mbox->m_in.status;		/*		 * decrement the pending queue counter		 */		atomic_sub(nstatus, &adapter->pend_cmds);		memcpy(completed, (void *)adapter->mbox->m_in.completed, 				nstatus);		/* Acknowledge interrupt */		irq_ack(adapter);		mega_cmd_done(adapter, completed, nstatus, status);		mega_rundoneq(adapter);		handled = 1;		/* Loop through any pending requests */		if(atomic_read(&adapter->quiescent) == 0) {			mega_runpendq(adapter);		}	} while(1); out_unlock:	spin_unlock_irqrestore(&adapter->lock, flags);	return IRQ_RETVAL(handled);}/** * megaraid_isr_memmapped() * @irq - irq * @devp - pointer to our soft state * * Interrupt service routine for memory-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */static irqreturn_tmegaraid_isr_memmapped(int irq, void *devp){	adapter_t	*adapter = devp;	unsigned long	flags;	u8	status;	u32	dword = 0;	u8	nstatus;	u8	completed[MAX_FIRMWARE_STATUS];	int	handled = 0;	/*	 * loop till F/W has more commands for us to complete.	 */	spin_lock_irqsave(&adapter->lock, flags);	do {		/* Check if a valid interrupt is pending */		dword = RDOUTDOOR(adapter);		if(dword != 0x10001234) {			/*			 * No more pending commands			 */			goto out_unlock;		}		WROUTDOOR(adapter, 0x10001234);		while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus)				== 0xFF) {			cpu_relax();		}		adapter->mbox->m_in.numstatus = 0xFF;		status = adapter->mbox->m_in.status;		/*		 * decrement the pending queue counter		 */		atomic_sub(nstatus, &adapter->pend_cmds);		memcpy(completed, (void *)adapter->mbox->m_in.completed, 				nstatus);		/* Acknowledge interrupt */		WRINDOOR(adapter, 0x2);		handled = 1;		while( RDINDOOR(adapter) & 0x02 )			cpu_relax();		mega_cmd_done(adapter, completed, nstatus, status);		mega_rundoneq(adapter);		/* Loop through any pending requests */		if(atomic_read(&adapter->quiescent) == 0) {			mega_runpendq(adapter);		}	} while(1); out_unlock:	spin_unlock_irqrestore(&adapter->lock, flags);	return IRQ_RETVAL(handled);}/** * mega_cmd_done() * @adapter - pointer to our soft state * @completed - array of ids of completed commands * @nstatus - number of completed commands * @status - status of the last command completed * * Complete the comamnds and call the scsi mid-layer callback hooks. */static voidmega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status){	mega_ext_passthru	*epthru = NULL;	struct scatterlist	*sgl;	Scsi_Cmnd	*cmd = NULL;	mega_passthru	*pthru = NULL;	mbox_t	*mbox = NULL;	u8	c;	scb_t	*scb;	int	islogical;	int	cmdid;	int	i;	/*	 * for all the commands completed, call the mid-layer callback routine	 * and free the scb.	 */	for( i = 0; i < nstatus; i++ ) {		cmdid = completed[i];		if( cmdid == CMDID_INT_CMDS ) { /* internal command */			scb = &adapter->int_scb;			cmd = scb->cmd;			mbox = (mbox_t *)scb->raw_mbox;			/*			 * Internal command interface do not fire the extended			 * passthru or 64-bit passthru			 */			pthru = scb->pthru;		}		else {			scb = &adapter->scb_list[cmdid];			/*			 * Make sure f/w has completed a valid command			 */			if( !(scb->state & SCB_ISSUED) || scb->cmd == NULL ) {				printk(KERN_CRIT					"megaraid: invalid command ");				printk("Id %d, scb->state:%x, scsi cmd:%p\n",					cmdid, scb->state, scb->cmd);				continue;			}			/*			 * Was a abort issued for this command			 */			if( scb->state & SCB_ABORT ) {				printk(KERN_WARNING				"megaraid: aborted cmd %lx[%x] complete.\n",					scb->cmd->serial_number, scb->idx);				scb->cmd->result = (DID_ABORT << 16);				list_add_tail(SCSI_LIST(scb->cmd),						&adapter->completed_list);				mega_free_scb(adapter, scb);				continue;			}			/*			 * Was a reset issued for this command			 */			if( scb->state & SCB_RESET ) {				printk(KERN_WARNING				"megaraid: reset cmd %lx[%x] complete.\n",					scb->cmd->serial_number, scb->idx);				scb->cmd->result = (DID_RESET << 16);				list_add_tail(SCSI_LIST(scb->cmd),						&adapter->completed_list);				mega_free_scb (adapter, scb);				continue;			}			cmd = scb->cmd;			pthru = scb->pthru;			epthru = scb->epthru;			mbox = (mbox_t *)scb->raw_mbox;#if MEGA_HAVE_STATS			{			int	logdrv = mbox->m_out.logdrv;			islogical = adapter->logdrv_chan[cmd->channel];			/*			 * Maintain an error counter for the logical drive.			 * Some application like SNMP agent need such			 * statistics			 */			if( status && islogical && (cmd->cmnd[0] == READ_6 ||						cmd->cmnd[0] == READ_10 ||						cmd->cmnd[0] == READ_12)) {				/*				 * Logical drive number increases by 0x80 when				 * a logical drive is deleted				 */				adapter->rd_errors[logdrv%0x80]++;			}			if( status && islogical && (cmd->cmnd[0] == WRITE_6 ||						cmd->cmnd[0] == WRITE_10 ||						cmd->cmnd[0] == WRITE_12)) {				/*				 * Logical drive number increases by 0x80 when				 * a logical drive is deleted				 */				adapter->wr_errors[logdrv%0x80]++;			}			}#endif		}		/*		 * Do not return the presence of hard disk on the channel so,		 * inquiry sent, and returned data==hard disk or removable		 * hard disk and not logical, request should return failure! -		 * PJ		 */		islogical = adapter->logdrv_chan[cmd->device->channel];		if( cmd->cmnd[0] == INQUIRY && !islogical ) {			sgl = scsi_sglist(cmd);			if( sg_page(sgl) ) {				c = *(unsigned char *) sg_virt(&sgl[0]);			} else {				printk(KERN_WARNING				       "megaraid: invalid sg.\n");				c = 0;			}			if(IS_RAID_CH(adapter, cmd->device->channel) &&					((c & 0x1F ) == TYPE_DISK)) {				status = 0xF0;			}		}		/* clear result; otherwise, success returns corrupt value */		cmd->result = 0;		/* Convert MegaRAID status to Linux error code */		switch (status) {		case 0x00:	/* SUCCESS , i.e. SCSI_STATUS_GOOD */			cmd->result |= (DID_OK << 16);			break;		case 0x02:	/* ERROR_ABORTED, i.e.				   SCSI_STATUS_CHECK_CONDITION */			/* set sense_buffer and result fields */			if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU ||				mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) {				memcpy(cmd->sense_buffer, pthru->reqsensearea,						14);				cmd->result = (DRIVER_SENSE << 24) |					(DID_OK << 16) |					(CHECK_CONDITION << 1);			}			else {				if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) {					memcpy(cmd->sense_buffer,						epthru->reqsensearea, 14);					cmd->result = (DRIVER_SENSE << 24) |						(DID_OK << 16) |						(CHECK_CONDITION << 1);				} else {					cmd->sense_buffer[0] = 0x70;					cmd->sense_buffer[2] = ABORTED_COMMAND;					cmd->result |= (CHECK_CONDITION << 1);				}			}			break;		case 0x08:	/* ERR_DEST_DRIVE_FAILED, i.e.				   SCSI_STATUS_BUSY */			cmd->result |= (DID_BUS_BUSY << 16) | status;			break;		default:#if MEGA_HAVE_CLUSTERING			/*			 * If TEST_UNIT_READY fails, we know			 * MEGA_RESERVATION_STATUS failed			 */			if( cmd->cmnd[0] == TEST_UNIT_READY ) {				cmd->result |= (DID_ERROR << 16) |					(RESERVATION_CONFLICT << 1);			}			else			/*			 * Error code returned is 1 if Reserve or Release			 * failed or the input parameter is invalid			 */			if( status == 1 &&				(cmd->cmnd[0] == RESERVE ||					 cmd->cmnd[0] == RELEASE) ) {				cmd->result |= (DID_ERROR << 16) |					(RESERVATION_CONFLICT << 1);			}			else#endif				cmd->result |= (DID_BAD_TARGET << 16)|status;		}		/*		 * Only free SCBs for the commands coming down from the		 * mid-layer, not for which were issued internally		 *		 * For internal command, restore the status returned by the		 * firmware so that user can interpret it.		 */		if( cmdid == CMDID_INT_CMDS ) { /* internal command */			cmd->result = status;			/*			 * Remove the internal command from the pending list			 */			list_del_init(&scb->list);			scb->state = SCB_FREE;		}		else {			mega_free_scb(adapter, scb);		}		/* Add Scsi_Command to end of completed queue */		list_add_tail(SCSI_LIST(cmd), &adapter->completed_list);	}}/* * mega_runpendq() * * Run through the list of completed requests and finish it */static voidmega_rundoneq (adapter_t *adapter){	Scsi_Cmnd *cmd;	struct list_head *pos;	list_for_each(pos, &adapter->completed_list) {		struct scsi_pointer* spos = (struct scsi_pointer *)pos;		cmd = list_entry(spos, Scsi_Cmnd, SCp);		cmd->scsi_done(cmd);	}	INIT_LIST_HEAD(&adapter->completed_list);}/*

⌨️ 快捷键说明

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