megaraid_sas.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,625 行 · 第 1/5 页

C
2,625
字号
}/** * megasas_get_controller_info -	Returns FW's controller structure * @instance:				Adapter soft state * @ctrl_info:				Controller information structure * * Issues an internal command (DCMD) to get the FW's controller structure. * This information is mainly used to find out the maximum IO transfer per * command supported by the FW. */static intmegasas_get_ctrl_info(struct megasas_instance *instance,		      struct megasas_ctrl_info *ctrl_info){	int ret = 0;	struct megasas_cmd *cmd;	struct megasas_dcmd_frame *dcmd;	struct megasas_ctrl_info *ci;	dma_addr_t ci_h = 0;	cmd = megasas_get_cmd(instance);	if (!cmd) {		printk(KERN_DEBUG "megasas: Failed to get a free cmd\n");		return -ENOMEM;	}	dcmd = &cmd->frame->dcmd;	ci = pci_alloc_consistent(instance->pdev,				  sizeof(struct megasas_ctrl_info), &ci_h);	if (!ci) {		printk(KERN_DEBUG "Failed to alloc mem for ctrl info\n");		megasas_return_cmd(instance, cmd);		return -ENOMEM;	}	memset(ci, 0, sizeof(*ci));	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);	dcmd->cmd = MFI_CMD_DCMD;	dcmd->cmd_status = 0xFF;	dcmd->sge_count = 1;	dcmd->flags = MFI_FRAME_DIR_READ;	dcmd->timeout = 0;	dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);	dcmd->opcode = MR_DCMD_CTRL_GET_INFO;	dcmd->sgl.sge32[0].phys_addr = ci_h;	dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info);	if (!megasas_issue_polled(instance, cmd)) {		ret = 0;		memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));	} else {		ret = -1;	}	pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),			    ci, ci_h);	megasas_return_cmd(instance, cmd);	return ret;}/** * megasas_init_mfi -	Initializes the FW * @instance:		Adapter soft state * * This is the main function for initializing MFI firmware. */static int megasas_init_mfi(struct megasas_instance *instance){	u32 context_sz;	u32 reply_q_sz;	u32 max_sectors_1;	u32 max_sectors_2;	struct megasas_register_set __iomem *reg_set;	struct megasas_cmd *cmd;	struct megasas_ctrl_info *ctrl_info;	struct megasas_init_frame *init_frame;	struct megasas_init_queue_info *initq_info;	dma_addr_t init_frame_h;	dma_addr_t initq_info_h;	/*	 * Map the message registers	 */	instance->base_addr = pci_resource_start(instance->pdev, 0);	if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {		printk(KERN_DEBUG "megasas: IO memory region busy!\n");		return -EBUSY;	}	instance->reg_set = ioremap_nocache(instance->base_addr, 8192);	if (!instance->reg_set) {		printk(KERN_DEBUG "megasas: Failed to map IO mem\n");		goto fail_ioremap;	}	reg_set = instance->reg_set;	switch(instance->pdev->device)	{		case PCI_DEVICE_ID_LSI_SAS1078R:				instance->instancet = &megasas_instance_template_ppc;			break;		case PCI_DEVICE_ID_LSI_SAS1064R:		case PCI_DEVICE_ID_DELL_PERC5:		default:			instance->instancet = &megasas_instance_template_xscale;			break;	}	/*	 * We expect the FW state to be READY	 */	if (megasas_transition_to_ready(instance))		goto fail_ready_state;	/*	 * Get various operational parameters from status register	 */	instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;	instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> 					0x10;	/*	 * Create a pool of commands	 */	if (megasas_alloc_cmds(instance))		goto fail_alloc_cmds;	/*	 * Allocate memory for reply queue. Length of reply queue should	 * be _one_ more than the maximum commands handled by the firmware.	 *	 * Note: When FW completes commands, it places corresponding contex	 * values in this circular reply queue. This circular queue is a fairly	 * typical producer-consumer queue. FW is the producer (of completed	 * commands) and the driver is the consumer.	 */	context_sz = sizeof(u32);	reply_q_sz = context_sz * (instance->max_fw_cmds + 1);	instance->reply_queue = pci_alloc_consistent(instance->pdev,						     reply_q_sz,						     &instance->reply_queue_h);	if (!instance->reply_queue) {		printk(KERN_DEBUG "megasas: Out of DMA mem for reply queue\n");		goto fail_reply_queue;	}	/*	 * Prepare a init frame. Note the init frame points to queue info	 * structure. Each frame has SGL allocated after first 64 bytes. For	 * this frame - since we don't need any SGL - we use SGL's space as	 * queue info structure	 *	 * We will not get a NULL command below. We just created the pool.	 */	cmd = megasas_get_cmd(instance);	init_frame = (struct megasas_init_frame *)cmd->frame;	initq_info = (struct megasas_init_queue_info *)	    ((unsigned long)init_frame + 64);	init_frame_h = cmd->frame_phys_addr;	initq_info_h = init_frame_h + 64;	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;	initq_info->producer_index_phys_addr_lo = instance->producer_h;	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;	init_frame->cmd = MFI_CMD_INIT;	init_frame->cmd_status = 0xFF;	init_frame->queue_info_new_phys_addr_lo = initq_info_h;	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);	/*	 * Issue the init frame in polled mode	 */	if (megasas_issue_polled(instance, cmd)) {		printk(KERN_DEBUG "megasas: Failed to init firmware\n");		goto fail_fw_init;	}	megasas_return_cmd(instance, cmd);	ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);	/*	 * Compute the max allowed sectors per IO: The controller info has two	 * limits on max sectors. Driver should use the minimum of these two.	 *	 * 1 << stripe_sz_ops.min = max sectors per strip	 *	 * Note that older firmwares ( < FW ver 30) didn't report information	 * to calculate max_sectors_1. So the number ended up as zero always.	 */	if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {		max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *		    ctrl_info->max_strips_per_io;		max_sectors_2 = ctrl_info->max_request_size;		instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)		    ? max_sectors_1 : max_sectors_2;	} else		instance->max_sectors_per_req = instance->max_num_sge *		    PAGE_SIZE / 512;	kfree(ctrl_info);	return 0;      fail_fw_init:	megasas_return_cmd(instance, cmd);	pci_free_consistent(instance->pdev, reply_q_sz,			    instance->reply_queue, instance->reply_queue_h);      fail_reply_queue:	megasas_free_cmds(instance);      fail_alloc_cmds:      fail_ready_state:	iounmap(instance->reg_set);      fail_ioremap:	pci_release_regions(instance->pdev);	return -EINVAL;}/** * megasas_release_mfi -	Reverses the FW initialization * @intance:			Adapter soft state */static void megasas_release_mfi(struct megasas_instance *instance){	u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);	pci_free_consistent(instance->pdev, reply_q_sz,			    instance->reply_queue, instance->reply_queue_h);	megasas_free_cmds(instance);	iounmap(instance->reg_set);	pci_release_regions(instance->pdev);}/** * megasas_get_seq_num -	Gets latest event sequence numbers * @instance:			Adapter soft state * @eli:			FW event log sequence numbers information * * FW maintains a log of all events in a non-volatile area. Upper layers would * usually find out the latest sequence number of the events, the seq number at * the boot etc. They would "read" all the events below the latest seq number * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq * number), they would subsribe to AEN (asynchronous event notification) and * wait for the events to happen. */static intmegasas_get_seq_num(struct megasas_instance *instance,		    struct megasas_evt_log_info *eli){	struct megasas_cmd *cmd;	struct megasas_dcmd_frame *dcmd;	struct megasas_evt_log_info *el_info;	dma_addr_t el_info_h = 0;	cmd = megasas_get_cmd(instance);	if (!cmd) {		return -ENOMEM;	}	dcmd = &cmd->frame->dcmd;	el_info = pci_alloc_consistent(instance->pdev,				       sizeof(struct megasas_evt_log_info),				       &el_info_h);	if (!el_info) {		megasas_return_cmd(instance, cmd);		return -ENOMEM;	}	memset(el_info, 0, sizeof(*el_info));	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);	dcmd->cmd = MFI_CMD_DCMD;	dcmd->cmd_status = 0x0;	dcmd->sge_count = 1;	dcmd->flags = MFI_FRAME_DIR_READ;	dcmd->timeout = 0;	dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);	dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;	dcmd->sgl.sge32[0].phys_addr = el_info_h;	dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_log_info);	megasas_issue_blocked_cmd(instance, cmd);	/*	 * Copy the data back into callers buffer	 */	memcpy(eli, el_info, sizeof(struct megasas_evt_log_info));	pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),			    el_info, el_info_h);	megasas_return_cmd(instance, cmd);	return 0;}/** * megasas_register_aen -	Registers for asynchronous event notification * @instance:			Adapter soft state * @seq_num:			The starting sequence number * @class_locale:		Class of the event * * This function subscribes for AEN for events beyond the @seq_num. It requests * to be notified if and only if the event is of type @class_locale */static intmegasas_register_aen(struct megasas_instance *instance, u32 seq_num,		     u32 class_locale_word){	int ret_val;	struct megasas_cmd *cmd;	struct megasas_dcmd_frame *dcmd;	union megasas_evt_class_locale curr_aen;	union megasas_evt_class_locale prev_aen;	/*	 * If there an AEN pending already (aen_cmd), check if the	 * class_locale of that pending AEN is inclusive of the new	 * AEN request we currently have. If it is, then we don't have	 * to do anything. In other words, whichever events the current	 * AEN request is subscribing to, have already been subscribed	 * to.	 *	 * If the old_cmd is _not_ inclusive, then we have to abort	 * that command, form a class_locale that is superset of both	 * old and current and re-issue to the FW	 */	curr_aen.word = class_locale_word;	if (instance->aen_cmd) {		prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];		/*		 * A class whose enum value is smaller is inclusive of all		 * higher values. If a PROGRESS (= -1) was previously		 * registered, then a new registration requests for higher		 * classes need not be sent to FW. They are automatically		 * included.		 *		 * Locale numbers don't have such hierarchy. They are bitmap		 * values		 */		if ((prev_aen.members.class <= curr_aen.members.class) &&		    !((prev_aen.members.locale & curr_aen.members.locale) ^		      curr_aen.members.locale)) {			/*			 * Previously issued event registration includes			 * current request. Nothing to do.			 */			return 0;		} else {			curr_aen.members.locale |= prev_aen.members.locale;			if (prev_aen.members.class < curr_aen.members.class)				curr_aen.members.class = prev_aen.members.class;			instance->aen_cmd->abort_aen = 1;			ret_val = megasas_issue_blocked_abort_cmd(instance,								  instance->								  aen_cmd);			if (ret_val) {				printk(KERN_DEBUG "megasas: Failed to abort "				       "previous AEN command\n");				return ret_val;			}		}	}	cmd = megasas_get_cmd(instance);	if (!cmd)		return -ENOMEM;	dcmd = &cmd->frame->dcmd;	memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail));	/*	 * Prepare DCMD for aen registration	 */	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);	dcmd->cmd = MFI_CMD_DCMD;	dcmd->cmd_status = 0x0;	dcmd->sge_count = 1;	dcmd->flags = MFI_FRAME_DIR_READ;	dcmd->timeout = 0;	dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);	dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;	dcmd->mbox.w[0] = seq_num;	dcmd->mbox.w[1] = curr_aen.word;	dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;	dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);	/*	 * Store reference to the cmd used to register for AEN. When an	 * application wants us to register for AEN, we have to abort this	 * cmd and re-register with a new EVENT LOCALE supplied by that app	 */	instance->aen_cmd = cmd;	/*	 * Issue the aen registration frame	 */	instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);	return 0;}/** * megasas_start_aen -	Subscribes to AEN during driver load time * @instance:		Adapter soft state */static int megasas_start_aen(struct megasas_instance *instance){	struct megasas_evt_log_info eli;	union megasas_evt_class_locale class_locale;	/*	 * Get the latest sequence number from FW	 */	memset(&eli, 0, sizeof(eli));	if (megasas_get_seq_num(instance, &eli))		return -1;	/*	 * Register AEN with FW for latest sequence number plus 1	 */	class_locale.members.reserved = 0;	class_locale.members.locale = MR_EVT_LOCALE_ALL;	class_locale.members.class = MR_EVT_CLASS_DEBUG;	return megasas_register_aen(instance, eli.newest_seq_num + 1,				    class_locale.word);}/** * megasas_io_attach -	Attaches this driver to SCSI mid-layer * @instance:		Adapter soft state */static int megasas_io_attach(struct megasas_instance *instance){	struct Scsi_Host *host = instance->host;	/*	 * Export parameters required by SCSI mid-layer	 */	host->irq = instance->pdev->irq;	host->unique_id = instance->unique_id;	host->can_queue = instance->max_fw_cmds - MEGASAS_INT_CMDS;	host->this_id = instance->init_id;	host->sg_tablesize = instance->max_num_sge;	host->max_sectors = instance->max_sectors_per_req;	host->cmd_per_lun = 128;	host->max_channel = MEGASAS_MAX_CHANNELS - 1;	host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;	host->max_lun = MEGASAS_MAX_LUN;	host->max_cmd_len = 16;	/*	 * Notify the mid-layer about the new controller	 */	if (scsi_add_host(host, &instance->pdev->dev)) {		printk(KERN_DEBUG "megasas: scsi_add_host failed\n");		return -ENODEV;	}	/*	 * Trigger SCSI to scan our drives	 */	scsi_scan_host(host);	return 0;}/** * megasas_probe_one -	PCI hotplug entry point * @pdev:		PCI device structure * @id:			PCI ids of supported hotplugged adapter	 */static int __devinitmegasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id){	int rval;	struct Scsi_Host *host;	struct megasas_instance *instance;	/*	 * Announce PCI information	 */

⌨️ 快捷键说明

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