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

📄 megaraid_sas.c

📁 最新的Megaraid SAS卡驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 */static intmegasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,		   union megasas_sgl *mfi_sgl){	int i;	int sge_count;	struct scatterlist *os_sgl;	/*	 * Return 0 if there is no data transfer	 */	if (!scp->request_buffer || !scp->request_bufflen)		return 0;	if (!scp->use_sg) {		mfi_sgl->sge64[0].phys_addr = pci_map_single(instance->pdev,							     scp->							     request_buffer,							     scp->							     request_bufflen,							     scp->							     sc_data_direction);		mfi_sgl->sge64[0].length = scp->request_bufflen;		return 1;	}	os_sgl = (struct scatterlist *)scp->request_buffer;	sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,			       scp->sc_data_direction);	for (i = 0; i < sge_count; i++, os_sgl++) {		mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);		mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);	}	return sge_count;} /** * megasas_get_frame_count - Computes the number of frames * @sge_count		: number of sg elements * * Returns the number of frames required for numnber of sge's (sge_count) */static u32 megasas_get_frame_count(u8 sge_count){	int num_cnt;	int sge_bytes;	u32 sge_sz;	u32 frame_count=0;	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :	    sizeof(struct megasas_sge32);	/*	* Main frame can contain 2 SGEs for 64-bit SGLs and	* 3 SGEs for 32-bit SGLs	*/	if (IS_DMA64)		num_cnt = sge_count - 2;	else		num_cnt = sge_count - 3;	if(num_cnt>0){		sge_bytes = sge_sz * num_cnt;		frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +		    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;	}	/* Main frame */	frame_count +=1;	if (frame_count > 7)		frame_count = 8;	return frame_count;}/** * megasas_build_dcdb -	Prepares a direct cdb (DCDB) command * @instance:		Adapter soft state * @scp:		SCSI command * @cmd:		Command to be prepared in * * This function prepares CDB commands. These are typcially pass-through * commands to the devices. */static intmegasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,		   struct megasas_cmd *cmd){	u32 is_logical;	u32 device_id;	u16 flags = 0;	struct megasas_pthru_frame *pthru;	is_logical = MEGASAS_IS_LOGICAL(scp);	device_id = MEGASAS_DEV_INDEX(instance, scp);	pthru = (struct megasas_pthru_frame *)cmd->frame;	if (scp->sc_data_direction == PCI_DMA_TODEVICE)		flags = MFI_FRAME_DIR_WRITE;	else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)		flags = MFI_FRAME_DIR_READ;	else if (scp->sc_data_direction == PCI_DMA_NONE)		flags = MFI_FRAME_DIR_NONE;	/*	 * Prepare the DCDB frame	 */	pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;	pthru->cmd_status = 0x0;	pthru->scsi_status = 0x0;	pthru->target_id = device_id;	pthru->lun = scp->device->lun;	pthru->cdb_len = scp->cmd_len;	pthru->timeout = 0;	pthru->flags = flags;	pthru->data_xfer_len = scp->request_bufflen;	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);	/*	 * Construct SGL	 */	if (IS_DMA64) {		pthru->flags |= MFI_FRAME_SGL64;		pthru->sge_count = megasas_make_sgl64(instance, scp,						      &pthru->sgl);	} else		pthru->sge_count = megasas_make_sgl32(instance, scp,						      &pthru->sgl);	/*	 * Sense info specific	 */	pthru->sense_len = SCSI_SENSE_BUFFERSIZE;	pthru->sense_buf_phys_addr_hi = 0;	pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;	/*	 * Compute the total number of frames this command consumes. FW uses	 * this number to pull sufficient number of frames from host memory.	 */	cmd->frame_count = megasas_get_frame_count(pthru->sge_count);	return cmd->frame_count;}/** * megasas_build_ldio -	Prepares IOs to logical devices * @instance:		Adapter soft state * @scp:		SCSI command * @cmd:		Command to to be prepared * * Frames (and accompanying SGLs) for regular SCSI IOs use this function. */static intmegasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,		   struct megasas_cmd *cmd){	u32 device_id;	u8 sc = scp->cmnd[0];	u16 flags = 0;	struct megasas_io_frame *ldio;	device_id = MEGASAS_DEV_INDEX(instance, scp);	ldio = (struct megasas_io_frame *)cmd->frame;	if (scp->sc_data_direction == PCI_DMA_TODEVICE)		flags = MFI_FRAME_DIR_WRITE;	else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)		flags = MFI_FRAME_DIR_READ;	/*	 * Prepare the Logical IO frame: 2nd bit is zero for all read cmds	 */	ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;	ldio->cmd_status = 0x0;	ldio->scsi_status = 0x0;	ldio->target_id = device_id;	ldio->timeout = 0;	ldio->reserved_0 = 0;	ldio->pad_0 = 0;	ldio->flags = flags;	ldio->start_lba_hi = 0;	ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;	/*	 * 6-byte READ(0x08) or WRITE(0x0A) cdb	 */	if (scp->cmd_len == 6) {		ldio->lba_count = (u32) scp->cmnd[4];		ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) |		    ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];		ldio->start_lba_lo &= 0x1FFFFF;	}	/*	 * 10-byte READ(0x28) or WRITE(0x2A) cdb	 */	else if (scp->cmd_len == 10) {		ldio->lba_count = (u32) scp->cmnd[8] |		    ((u32) scp->cmnd[7] << 8);		ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |		    ((u32) scp->cmnd[3] << 16) |		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];	}	/*	 * 12-byte READ(0xA8) or WRITE(0xAA) cdb	 */	else if (scp->cmd_len == 12) {		ldio->lba_count = ((u32) scp->cmnd[6] << 24) |		    ((u32) scp->cmnd[7] << 16) |		    ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];		ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |		    ((u32) scp->cmnd[3] << 16) |		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];	}	/*	 * 16-byte READ(0x88) or WRITE(0x8A) cdb	 */	else if (scp->cmd_len == 16) {		ldio->lba_count = ((u32) scp->cmnd[10] << 24) |		    ((u32) scp->cmnd[11] << 16) |		    ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];		ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) |		    ((u32) scp->cmnd[7] << 16) |		    ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];		ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) |		    ((u32) scp->cmnd[3] << 16) |		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];	}	/*	 * Construct SGL	 */	if (IS_DMA64) {		ldio->flags |= MFI_FRAME_SGL64;		ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);	} else		ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);	/*	 * Sense info specific	 */	ldio->sense_len = SCSI_SENSE_BUFFERSIZE;	ldio->sense_buf_phys_addr_hi = 0;	ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;	/*	 * Compute the total number of frames this command consumes. FW uses	 * this number to pull sufficient number of frames from host memory.	 */	cmd->frame_count = megasas_get_frame_count(ldio->sge_count);	return cmd->frame_count;}/** * megasas_is_ldio -		Checks if the cmd is for logical drive * @scmd:			SCSI command *	 * Called by megasas_queue_command to find out if the command to be queued * is a logical drive command	 */static inline int megasas_is_ldio(struct scsi_cmnd *cmd){	if (!MEGASAS_IS_LOGICAL(cmd))		return 0;	switch (cmd->cmnd[0]) {	case READ_10:	case WRITE_10:	case READ_12:	case WRITE_12:	case READ_6:	case WRITE_6:	case READ_16:	case WRITE_16:		return 1;	default:		return 0;	}} /** * megasas_dump_pending_frames -	Dumps the frame address of all pending cmds *                              	in FW * @instance:				Adapter soft state */static inline voidmegasas_dump_pending_frames(struct megasas_instance *instance){	struct megasas_cmd *cmd;	int i,n;	union megasas_sgl *mfi_sgl;	struct megasas_io_frame *ldio;	struct megasas_pthru_frame *pthru;	u32 sgcount;	u32 max_cmd = instance->max_fw_cmds;	printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);	printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));	if (IS_DMA64)		printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);	else		printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);	printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);	for (i = 0; i < max_cmd; i++) {		cmd = instance->cmd_list[i];		if(!cmd->scmd)			continue;		printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);		if (megasas_is_ldio(cmd->scmd)){			ldio = (struct megasas_io_frame *)cmd->frame;			mfi_sgl = &ldio->sgl;			sgcount = ldio->sge_count;			printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);		}		else {			pthru = (struct megasas_pthru_frame *) cmd->frame;			mfi_sgl = &pthru->sgl;			sgcount = pthru->sge_count;			printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);		}	if(megasas_dbg_lvl & MEGASAS_DBG_LVL){		for (n = 0; n < sgcount; n++){			if (IS_DMA64)				printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;			else				printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;			}		}		printk(KERN_ERR "\n");	} /*for max_cmd*/	printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);	for (i = 0; i < max_cmd; i++) {		cmd = instance->cmd_list[i];		if(cmd->sync_cmd == 1){			printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);		}	}	printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);}/** * megasas_queue_command -	Queue entry point * @scmd:			SCSI command to be queued * @done:			Callback entry point */static intmegasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)){	u32 frame_count;	struct megasas_cmd *cmd;	struct megasas_instance *instance;	instance = (struct megasas_instance *)	    scmd->device->host->hostdata;	/* Don't process if we have already declared adapter dead */	if (instance->hw_crit_error)		return SCSI_MLQUEUE_HOST_BUSY;	scmd->scsi_done = done;	scmd->result = 0;	if (MEGASAS_IS_LOGICAL(scmd) &&	    (scmd->device->id >= MEGASAS_MAX_LD || scmd->device->lun)) {		scmd->result = DID_BAD_TARGET << 16;		goto out_done;	}	switch (scmd->cmnd[0]) {	case SYNCHRONIZE_CACHE:		/*		 * FW takes care of flush cache on its own		 * No need to send it down		 */		scmd->result = DID_OK << 16;		goto out_done;	}	cmd = megasas_get_cmd(instance);	if (!cmd)		return SCSI_MLQUEUE_HOST_BUSY;	/*	 * Logical drive command	 */	if (megasas_is_ldio(scmd))		frame_count = megasas_build_ldio(instance, scmd, cmd);	else		frame_count = megasas_build_dcdb(instance, scmd, cmd);	if (!frame_count)		goto out_return_cmd;	cmd->scmd = scmd;	scmd->SCp.ptr = (char *)cmd;	/*	 * Issue the command to the FW	 */	atomic_inc(&instance->fw_outstanding);	instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);	return 0; out_return_cmd:	megasas_return_cmd(instance, cmd); out_done:	done(scmd);	return 0;}static int megasas_slave_configure(struct scsi_device *sdev){	/*	 * Don't export physical disk devices to the disk driver.	 *	 * FIXME: Currently we don't export them to the midlayer at all.	 * 	  That will be fixed once LSI engineers have audited the	 * 	  firmware for possible issues.	 */	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)		return -ENXIO;	/*	 * The RAID firmware may require extended timeouts.	 */	if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)		sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ;	return 0;}/** * megasas_complete_cmd_dpc	 -	Returns FW's controller structure * @instance_addr:			Address of adapter soft state * * Tasklet to complete cmds */static void megasas_complete_cmd_dpc(unsigned long instance_addr){	u32 producer;	u32 consumer;	u32 context;	struct megasas_cmd *cmd;	struct megasas_instance *instance = (struct megasas_instance *)instance_addr;	unsigned long flags;	/* If we have already declared adapter dead, donot complete cmds */	if (instance->hw_crit_error)		return;	spin_lock_irqsave(&instance->completion_lock, flags);	producer = *instance->producer;	consumer = *instance->consumer;	while (consumer != producer) {		context = instance->reply_queue[consumer];		cmd = instance->cmd_list[context];		megasas_complete_cmd(instance, cmd, DID_OK);		consumer++;		if (consumer == (instance->max_fw_cmds + 1)) {			consumer = 0;		}	}	*instance->consumer = producer;	spin_unlock_irqrestore(&instance->completion_lock, flags);}/** * megasas_wait_for_outstanding -	Wait for all outstanding cmds * @instance:				Adapter soft state * * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to * complete all its outstanding commands. Returns error if one or more IOs * are pending after this time period. It also marks the controller dead. */static int megasas_wait_for_outstanding(struct megasas_instance *instance){	int i;	u32 wait_time = MEGASAS_RESET_WAIT_TIME;	for (i = 0; i < wait_time; i++) {		int outstanding = atomic_read(&instance->fw_outstanding);

⌨️ 快捷键说明

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