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

📄 megaraid_sas.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	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;	/*	 * We expect the FW state to be READY	 */	if (megasas_transition_to_ready(instance->reg_set))		goto fail_ready_state;	/*	 * Get various operational parameters from status register	 */	instance->max_fw_cmds = readl(&reg_set->outbound_msg_0) & 0x00FFFF;	instance->max_num_sge = (readl(&reg_set->outbound_msg_0) & 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	 */	writel(cmd->frame_phys_addr >> 3,	       &instance->reg_set->inbound_queue_port);	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;	/*	 * 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	 */	printk(KERN_INFO "megasas: %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",	       pdev->vendor, pdev->device, pdev->subsystem_vendor,	       pdev->subsystem_device);	printk("bus %d:slot %d:func %d\n",	       pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));	/*	 * PCI prepping: enable device set bus mastering and dma mask	 */	rval = pci_enable_device(pdev);	if (rval) {		return rval;	}	pci_set_master(pdev);	/*	 * All our contollers are capable of performing 64-bit DMA	 */	if (IS_DMA64) {		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)				goto fail_set_dma_mask;		}	} else {		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)			goto fail_set_dma_mask;	}	host = scsi_host_alloc(&megasas_template,			       sizeof(struct megasas_instance));	if (!host) {		printk(KERN_DEBUG "megasas: scsi_host_alloc failed\n");		goto fail_alloc_instance;	}	instance = (struct megasas_instance *)host->hostdata;	memset(instance, 0, sizeof(*instance));	instance->producer = pci_alloc_consistent(pdev, sizeof(u32),						  &instance->producer_h);	instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),						  &instance->consumer_h);	if (!instance->producer || !instance->consumer) {		printk(KERN_DEBUG "megasas: Failed to allocate memory for "		       "producer, consumer\n");		goto fail_alloc_dma_buf;	}	*instance->producer = 0;	*instance->consumer = 0;	instance->evt_detail = pci_alloc_consistent(pdev,						    sizeof(struct							   megasas_evt_detail),						    &instance->evt_detail_h);	if (!instance->evt_detail) {		printk(KERN_DEBUG "megasas: Failed to allocate memory for "		       "event detail structure\n");		goto fail_alloc_dma_buf;	}	/*	 * Initialize locks and queues	 */	INIT_LIST_HEAD(&instance->cmd_pool);	init_waitqueue_head(&instance->int_cmd_wait_q);	init_waitqueue_head(&instance->abort_cmd_wait_q);	spin_lock_init(&instance->cmd_pool_lock);	spin_lock_init(&instance->instance_lock);	sema_init(&instance->aen_mutex, 1);	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);	/*	 * Initialize PCI related and misc parameters	 */	instance->pdev = pdev;	instance->host = host;	instance->unique_id = pdev->bus->number << 8 | pdev->devfn;	instance->init_id = MEGASAS_DEFAULT_INIT_ID;	/*	 * Initialize MFI Firmware	 */	if (megasas_init_mfi(instance))		goto fail_init_mfi;	/*	 * Register IRQ	 */	if (request_irq(pdev->irq, megasas_isr, SA_SHIRQ, "megasas", instance)) {		printk(KERN_DEBUG "megasas: Failed to register IRQ\n");

⌨️ 快捷键说明

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