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

📄 megaraid_sas.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :	    sizeof(struct megasas_sge32);	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;	sge_bytes = sge_sz * ldio->sge_count;	cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +	    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;	if (cmd->frame_count > 7)		cmd->frame_count = 8;	return cmd->frame_count;}/** * megasas_build_cmd -	Prepares a command packet * @instance:		Adapter soft state * @scp:		SCSI command * @frame_count:	[OUT] Number of frames used to prepare this command */static inline struct megasas_cmd *megasas_build_cmd(struct megasas_instance						    *instance,						    struct scsi_cmnd *scp,						    int *frame_count){	u32 logical_cmd;	struct megasas_cmd *cmd;	/*	 * Find out if this is logical or physical drive command.	 */	logical_cmd = MEGASAS_IS_LOGICAL(scp);	/*	 * Logical drive command	 */	if (logical_cmd) {		if (scp->device->id >= MEGASAS_MAX_LD) {			scp->result = DID_BAD_TARGET << 16;			return NULL;		}		switch (scp->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:			/*			 * Fail for LUN > 0			 */			if (scp->device->lun) {				scp->result = DID_BAD_TARGET << 16;				return NULL;			}			cmd = megasas_get_cmd(instance);			if (!cmd) {				scp->result = DID_IMM_RETRY << 16;				return NULL;			}			*frame_count = megasas_build_ldio(instance, scp, cmd);			if (!(*frame_count)) {				megasas_return_cmd(instance, cmd);				return NULL;			}			return cmd;		default:			/*			 * Fail for LUN > 0			 */			if (scp->device->lun) {				scp->result = DID_BAD_TARGET << 16;				return NULL;			}			cmd = megasas_get_cmd(instance);			if (!cmd) {				scp->result = DID_IMM_RETRY << 16;				return NULL;			}			*frame_count = megasas_build_dcdb(instance, scp, cmd);			if (!(*frame_count)) {				megasas_return_cmd(instance, cmd);				return NULL;			}			return cmd;		}	} else {		cmd = megasas_get_cmd(instance);		if (!cmd) {			scp->result = DID_IMM_RETRY << 16;			return NULL;		}		*frame_count = megasas_build_dcdb(instance, scp, cmd);		if (!(*frame_count)) {			megasas_return_cmd(instance, cmd);			return NULL;		}		return cmd;	}	return NULL;}/** * 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;	unsigned long flags;	struct megasas_cmd *cmd;	struct megasas_instance *instance;	instance = (struct megasas_instance *)	    scmd->device->host->hostdata;	scmd->scsi_done = done;	scmd->result = 0;	cmd = megasas_build_cmd(instance, scmd, &frame_count);	if (!cmd) {		done(scmd);		return 0;	}	cmd->scmd = scmd;	scmd->SCp.ptr = (char *)cmd;	scmd->SCp.sent_command = jiffies;	/*	 * Issue the command to the FW	 */	spin_lock_irqsave(&instance->instance_lock, flags);	instance->fw_outstanding++;	spin_unlock_irqrestore(&instance->instance_lock, flags);	writel(((cmd->frame_phys_addr >> 3) | (cmd->frame_count - 1)),	       &instance->reg_set->inbound_queue_port);	return 0;}/** * 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++) {		if (!instance->fw_outstanding)			break;		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "			       "commands to complete\n", i,			       instance->fw_outstanding);		}		msleep(1000);	}	if (instance->fw_outstanding) {		instance->hw_crit_error = 1;		return FAILED;	}	return SUCCESS;}/** * megasas_generic_reset -	Generic reset routine * @scmd:			Mid-layer SCSI command * * This routine implements a generic reset handler for device, bus and host * reset requests. Device, bus and host specific reset handlers can use this * function after they do their specific tasks. */static int megasas_generic_reset(struct scsi_cmnd *scmd){	int ret_val;	struct megasas_instance *instance;	instance = (struct megasas_instance *)scmd->device->host->hostdata;	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x\n",	       scmd->serial_number, scmd->cmnd[0]);	if (instance->hw_crit_error) {		printk(KERN_ERR "megasas: cannot recover from previous reset "		       "failures\n");		return FAILED;	}	ret_val = megasas_wait_for_outstanding(instance);	if (ret_val == SUCCESS)		printk(KERN_NOTICE "megasas: reset successful \n");	else		printk(KERN_ERR "megasas: failed to do reset\n");	return ret_val;}static enum scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd){	unsigned long seconds;	if (scmd->SCp.ptr) {		seconds = (jiffies - scmd->SCp.sent_command) / HZ;		if (seconds < 90) {			return EH_RESET_TIMER;		} else {			return EH_NOT_HANDLED;		}	}	return EH_HANDLED;}/** * megasas_reset_device -	Device reset handler entry point */static int megasas_reset_device(struct scsi_cmnd *scmd){	int ret;	/*	 * First wait for all commands to complete	 */	ret = megasas_generic_reset(scmd);	return ret;}/** * megasas_reset_bus_host -	Bus & host reset handler entry point */static int megasas_reset_bus_host(struct scsi_cmnd *scmd){	int ret;	/*	 * Frist wait for all commands to complete	 */	ret = megasas_generic_reset(scmd);	return ret;}/** * megasas_service_aen -	Processes an event notification * @instance:			Adapter soft state * @cmd:			AEN command completed by the ISR * * For AEN, driver sends a command down to FW that is held by the FW till an * event occurs. When an event of interest occurs, FW completes the command * that it was previously holding. * * This routines sends SIGIO signal to processes that have registered with the * driver for AEN. */static voidmegasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd){	/*	 * Don't signal app if it is just an aborted previously registered aen	 */	if (!cmd->abort_aen)		kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);	else		cmd->abort_aen = 0;	instance->aen_cmd = NULL;	megasas_return_cmd(instance, cmd);}/* * Scsi host template for megaraid_sas driver */static struct scsi_host_template megasas_template = {	.module = THIS_MODULE,	.name = "LSI Logic SAS based MegaRAID driver",	.proc_name = "megaraid_sas",	.queuecommand = megasas_queue_command,	.eh_device_reset_handler = megasas_reset_device,	.eh_bus_reset_handler = megasas_reset_bus_host,	.eh_host_reset_handler = megasas_reset_bus_host,	.eh_timed_out = megasas_reset_timer,	.use_clustering = ENABLE_CLUSTERING,};/** * megasas_complete_int_cmd -	Completes an internal command * @instance:			Adapter soft state * @cmd:			Command to be completed * * The megasas_issue_blocked_cmd() function waits for a command to complete * after it issues a command. This function wakes up that waiting routine by * calling wake_up() on the wait queue. */static voidmegasas_complete_int_cmd(struct megasas_instance *instance,			 struct megasas_cmd *cmd){	cmd->cmd_status = cmd->frame->io.cmd_status;	if (cmd->cmd_status == ENODATA) {		cmd->cmd_status = 0;	}	wake_up(&instance->int_cmd_wait_q);}/** * megasas_complete_abort -	Completes aborting a command * @instance:			Adapter soft state * @cmd:			Cmd that was issued to abort another cmd * * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q  * after it issues an abort on a previously issued command. This function  * wakes up all functions waiting on the same wait queue. */static voidmegasas_complete_abort(struct megasas_instance *instance,		       struct megasas_cmd *cmd){	if (cmd->sync_cmd) {		cmd->sync_cmd = 0;		cmd->cmd_status = 0;		wake_up(&instance->abort_cmd_wait_q);	}	return;}/** * megasas_unmap_sgbuf -	Unmap SG buffers * @instance:			Adapter soft state * @cmd:			Completed command */static inline voidmegasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd){	dma_addr_t buf_h;	u8 opcode;	if (cmd->scmd->use_sg) {		pci_unmap_sg(instance->pdev, cmd->scmd->request_buffer,			     cmd->scmd->use_sg, cmd->scmd->sc_data_direction);		return;	}	if (!cmd->scmd->request_bufflen)		return;	opcode = cmd->frame->hdr.cmd;	if ((opcode == MFI_CMD_LD_READ) || (opcode == MFI_CMD_LD_WRITE)) {		if (IS_DMA64)			buf_h = cmd->frame->io.sgl.sge64[0].phys_addr;		else			buf_h = cmd->frame->io.sgl.sge32[0].phys_addr;	} else {		if (IS_DMA64)			buf_h = cmd->frame->pthru.sgl.sge64[0].phys_addr;		else			buf_h = cmd->frame->pthru.sgl.sge32[0].phys_addr;	}	pci_unmap_single(instance->pdev, buf_h, cmd->scmd->request_bufflen,			 cmd->scmd->sc_data_direction);	return;}/** * megasas_complete_cmd -	Completes a command * @instance:			Adapter soft state * @cmd:			Command to be completed * @alt_status:			If non-zero, use this value as status to  * 				SCSI mid-layer instead of the value returned * 				by the FW. This should be used if caller wants * 				an alternate status (as in the case of aborted * 				commands) */static inline voidmegasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,		     u8 alt_status){	int exception = 0;	struct megasas_header *hdr = &cmd->frame->hdr;	unsigned long flags;	if (cmd->scmd) {		cmd->scmd->SCp.ptr = (char *)0;	}	switch (hdr->cmd) {	case MFI_CMD_PD_SCSI_IO:	case MFI_CMD_LD_SCSI_IO:		/*		 * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been		 * issued either through an IO path or an IOCTL path. If it		 * was via IOCTL, we will send it to internal completion.		 */		if (cmd->sync_cmd) {			cmd->sync_cmd = 0;			megasas_complete_int_cmd(instance, cmd);			break;		}		/*		 * Don't export physical disk devices to mid-layer.		 */		if (!MEGASAS_IS_LOGICAL(cmd->scmd) &&		    (hdr->cmd_status == MFI_STAT_OK) &&		    (cmd->scmd->cmnd[0] == INQUIRY)) {			if (((*(u8 *) cmd->scmd->request_buffer) & 0x1F) ==			    TYPE_DISK) {				cmd->scmd->result = DID_BAD_TARGET << 16;				exception = 1;			}		}	case MFI_CMD_LD_READ:	case MFI_CMD_LD_WRITE:		if (alt_status) {			cmd->scmd->result = alt_status << 16;			exception = 1;		}		if (exception) {			spin_lock_irqsave(&instance->instance_lock, flags);			instance->fw_outstanding--;			spin_unlock_irqrestore(&instance->instance_lock, flags);			megasas_unmap_sgbuf(instance, cmd);			cmd->scmd->scsi_done(cmd->scmd);			megasas_return_cmd(instance, cmd);			break;		}		switch (hdr->cmd_status) {		case MFI_STAT_OK:			cmd->scmd->result = DID_OK << 16;			break;		case MFI_STAT_SCSI_IO_FAILED:		case MFI_STAT_LD_INIT_IN_PROGRESS:			cmd->scmd->result =			    (DID_ERROR << 16) | hdr->scsi_status;			break;		case MFI_STAT_SCSI_DONE_WITH_ERROR:			cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status;			if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) {				memset(cmd->scmd->sense_buffer, 0,				       SCSI_SENSE_BUFFERSIZE);				memcpy(cmd->scmd->sense_buffer, cmd->sense,				       hdr->sense_len);				cmd->scmd->result |= DRIVER_SENSE << 24;			}			break;		case MFI_STAT_LD_OFFLINE:		case MFI_STAT_DEVICE_NOT_FOUND:			cmd->scmd->result = DID_BAD_TARGET << 16;			break;		default:			printk(KERN_DEBUG "megasas: MFI FW status %#x\n",			       hdr->cmd_status);			cmd->scmd->result = DID_ERROR << 16;			break;		}		spin_lock_irqsave(&instance->instance_lock, flags);

⌨️ 快捷键说明

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