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

📄 megaraid_sas.c

📁 最新的Megaraid SAS卡驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (!outstanding)			break;		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "			       "commands to complete\n",i,outstanding);			/*			 * Call cmd completion routine. Cmd to be 			 * be completed directly without depending on isr.			 */			megasas_complete_cmd_dpc((unsigned long)instance);		}		msleep(1000);	}	if (atomic_read(&instance->fw_outstanding)) {		/*		* Send signal to FW to stop processing any pending cmds.		* The controller will be taken offline by the OS now.		*/		writel(MFI_STOP_ADP,				&instance->reg_set->inbound_doorbell);		megasas_dump_pending_frames(instance);		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 retries=%x\n",		 scmd->serial_number, scmd->cmnd[0], scmd->retries);	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;} /** * megasas_reset_timer - quiesce the adapter if required * @scmd:		scsi cmnd * * Sets the FW busy flag and reduces the host->can_queue if the * cmd has not been completed within the timeout period. */static enumscsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd){	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;	struct megasas_instance *instance;	unsigned long flags;	if (time_after(jiffies, scmd->jiffies_at_alloc +				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {		return EH_NOT_HANDLED;	}	instance = cmd->instance;	if (!(instance->flag & MEGASAS_FW_BUSY)) {		/* FW is busy, throttle IO */		spin_lock_irqsave(instance->host->host_lock, flags);		instance->host->can_queue = 16;		instance->last_time = jiffies;		instance->flag |= MEGASAS_FW_BUSY;		spin_unlock_irqrestore(instance->host->host_lock, flags);	}	return EH_RESET_TIMER;}/** * 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;	/*	 * First wait for all commands to complete	 */	ret = megasas_generic_reset(scmd);	return ret;}/** * megasas_bios_param - Returns disk geometry for a disk * @sdev: 		device handle * @bdev:		block device * @capacity:		drive capacity * @geom:		geometry parameters */static intmegasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,		 sector_t capacity, int geom[]){	int heads;	int sectors;	sector_t cylinders;	unsigned long tmp;	/* Default heads (64) & sectors (32) */	heads = 64;	sectors = 32;	tmp = heads * sectors;	cylinders = capacity;	sector_div(cylinders, tmp);	/*	 * Handle extended translation size for logical drives > 1Gb	 */	if (capacity >= 0x200000) {		heads = 255;		sectors = 63;		tmp = heads*sectors;		cylinders = capacity;		sector_div(cylinders, tmp);	}	geom[0] = heads;	geom[1] = sectors;	geom[2] = cylinders;	return 0;}/** * 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);}static struct megasas_instance *megasas_lookup_instance(u16 host_no){	int i;	for (i = 0; i < megasas_mgmt_info.max_index; i++) {		if ((megasas_mgmt_info.instance[i]) &&		    (megasas_mgmt_info.instance[i]->host->host_no == host_no))			return megasas_mgmt_info.instance[i];	}	return NULL;}static int megasas_slave_alloc(struct scsi_device *sdev) {	struct megasas_instance *instance ;	int tmp_fastload = fast_load;	instance = megasas_lookup_instance(sdev->host->host_no);	if (tmp_fastload && sdev->channel < MEGASAS_MAX_PD_CHANNELS) {		if ((sdev->id == MEGASAS_MAX_DEV_PER_CHANNEL -1) &&			(sdev->channel == MEGASAS_MAX_PD_CHANNELS - 1)) {			/* If fast load option was set and scan for last device is			 * over, reset the fast_load flag so that during a possible			 * next scan, devices can be made available			 */			fast_load = 0;		}		return -ENXIO;	}	return 0;}/* * 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",	.slave_configure = megasas_slave_configure,	.slave_alloc = megasas_slave_alloc,	.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,	.bios_param = megasas_bios_param,	.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 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 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 = NULL;	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;		}	case MFI_CMD_LD_READ:	case MFI_CMD_LD_WRITE:		if (alt_status) {			cmd->scmd->result = alt_status << 16;			exception = 1;		}		if (exception) {			atomic_dec(&instance->fw_outstanding);			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;		}		atomic_dec(&instance->fw_outstanding);		megasas_unmap_sgbuf(instance, cmd);		cmd->scmd->scsi_done(cmd->scmd);		megasas_return_cmd(instance, cmd);		break;	case MFI_CMD_SMP:	case MFI_CMD_STP:	case MFI_CMD_DCMD:		/*		 * See if got an event notification		 */		if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)			megasas_service_aen(instance, cmd);		else			megasas_complete_int_cmd(instance, cmd);		break;	case MFI_CMD_ABORT:		/*		 * Cmd issued to abort another cmd returned		 */		megasas_complete_abort(instance, cmd);		break;	default:		printk("megasas: Unknown command completed! [0x%X]\n",		       hdr->cmd);		break;	}		/*	 * Check if we can restore can_queue	 */	if (instance->flag & MEGASAS_FW_BUSY		&& time_after(jiffies, instance->last_time + 5 * HZ)		&& atomic_read(&instance->fw_outstanding) < 17) {		spin_lock_irqsave(instance->host->host_lock, flags);		instance->flag &= ~MEGASAS_FW_BUSY;		instance->host->can_queue =				instance->max_fw_cmds - MEGASAS_INT_CMDS;		spin_unlock_irqrestore(instance->host->host_lock, flags);	}	}/** * megasas_deplete_reply_queue -	Processes all completed commands * @instance:				Adapter soft state * @alt_status:				Alternate status to be returned to * 					SCSI mid-layer instead of the status * 					returned by the FW */static intmegasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status){	/*	 * Check if it is our interrupt	 * Clear the interrupt 	 */	if(instance->instancet->clear_intr(instance->reg_set))		return IRQ_NONE;	if (instance->hw_crit_error)		goto out_done;        /*	 * Schedule the tasklet for cmd completion	 */	tasklet_schedule(&instance->isr_tasklet);out_done:	return IRQ_HANDLED;}/** * megasas_isr - isr entry point */

⌨️ 快捷键说明

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