ipr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,336 行 · 第 1/5 页

C
2,336
字号
		return -EIO;	}	/* Signal LDUMP interlocked - clear IO debug ack */	writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,	       ioa_cfg->regs.clr_interrupt_reg);	/* Write Mailbox with starting address */	writel(start_addr, ioa_cfg->ioa_mailbox);	/* Signal address valid - clear IOA Reset alert */	writel(IPR_UPROCI_RESET_ALERT,	       ioa_cfg->regs.clr_uproc_interrupt_reg);	for (i = 0; i < length_in_words; i++) {		/* Wait for IO debug acknowledge */		if (ipr_wait_iodbg_ack(ioa_cfg,				       IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC)) {			dev_err(&ioa_cfg->pdev->dev,				"IOA dump short data transfer timeout\n");			return -EIO;		}		/* Read data from mailbox and increment destination pointer */		*dest = cpu_to_be32(readl(ioa_cfg->ioa_mailbox));		dest++;		/* For all but the last word of data, signal data received */		if (i < (length_in_words - 1)) {			/* Signal dump data received - Clear IO debug Ack */			writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,			       ioa_cfg->regs.clr_interrupt_reg);		}	}	/* Signal end of block transfer. Set reset alert then clear IO debug ack */	writel(IPR_UPROCI_RESET_ALERT,	       ioa_cfg->regs.set_uproc_interrupt_reg);	writel(IPR_UPROCI_IO_DEBUG_ALERT,	       ioa_cfg->regs.clr_uproc_interrupt_reg);	/* Signal dump data received - Clear IO debug Ack */	writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,	       ioa_cfg->regs.clr_interrupt_reg);	/* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */	while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) {		temp_pcii_reg =		    readl(ioa_cfg->regs.sense_uproc_interrupt_reg);		if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT))			return 0;		udelay(10);		delay += 10;	}	return 0;}#ifdef CONFIG_SCSI_IPR_DUMP/** * ipr_sdt_copy - Copy Smart Dump Table to kernel buffer * @ioa_cfg:		ioa config struct * @pci_address:	adapter address * @length:			length of data to copy * * Copy data from PCI adapter to kernel buffer. * Note: length MUST be a 4 byte multiple * Return value: * 	0 on success / other on failure **/static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg,			unsigned long pci_address, u32 length){	int bytes_copied = 0;	int cur_len, rc, rem_len, rem_page_len;	u32 *page;	unsigned long lock_flags = 0;	struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump;	while (bytes_copied < length &&	       (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) {		if (ioa_dump->page_offset >= PAGE_SIZE ||		    ioa_dump->page_offset == 0) {			page = (u32 *)__get_free_page(GFP_ATOMIC);			if (!page) {				ipr_trace;				return bytes_copied;			}			ioa_dump->page_offset = 0;			ioa_dump->ioa_data[ioa_dump->next_page_index] = page;			ioa_dump->next_page_index++;		} else			page = ioa_dump->ioa_data[ioa_dump->next_page_index - 1];		rem_len = length - bytes_copied;		rem_page_len = PAGE_SIZE - ioa_dump->page_offset;		cur_len = min(rem_len, rem_page_len);		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);		if (ioa_cfg->sdt_state == ABORT_DUMP) {			rc = -EIO;		} else {			rc = ipr_get_ldump_data_section(ioa_cfg,							pci_address + bytes_copied,							&page[ioa_dump->page_offset / 4],							(cur_len / sizeof(u32)));		}		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		if (!rc) {			ioa_dump->page_offset += cur_len;			bytes_copied += cur_len;		} else {			ipr_trace;			break;		}		schedule();	}	return bytes_copied;}/** * ipr_init_dump_entry_hdr - Initialize a dump entry header. * @hdr:	dump entry header struct * * Return value: * 	nothing **/static void ipr_init_dump_entry_hdr(struct ipr_dump_entry_header *hdr){	hdr->eye_catcher = IPR_DUMP_EYE_CATCHER;	hdr->num_elems = 1;	hdr->offset = sizeof(*hdr);	hdr->status = IPR_DUMP_STATUS_SUCCESS;}/** * ipr_dump_ioa_type_data - Fill in the adapter type in the dump. * @ioa_cfg:	ioa config struct * @driver_dump:	driver dump struct * * Return value: * 	nothing **/static void ipr_dump_ioa_type_data(struct ipr_ioa_cfg *ioa_cfg,				   struct ipr_driver_dump *driver_dump){	struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;	ipr_init_dump_entry_hdr(&driver_dump->ioa_type_entry.hdr);	driver_dump->ioa_type_entry.hdr.len =		sizeof(struct ipr_dump_ioa_type_entry) -		sizeof(struct ipr_dump_entry_header);	driver_dump->ioa_type_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;	driver_dump->ioa_type_entry.hdr.id = IPR_DUMP_DRIVER_TYPE_ID;	driver_dump->ioa_type_entry.type = ioa_cfg->type;	driver_dump->ioa_type_entry.fw_version = (ucode_vpd->major_release << 24) |		(ucode_vpd->card_type << 16) | (ucode_vpd->minor_release[0] << 8) |		ucode_vpd->minor_release[1];	driver_dump->hdr.num_entries++;}/** * ipr_dump_version_data - Fill in the driver version in the dump. * @ioa_cfg:	ioa config struct * @driver_dump:	driver dump struct * * Return value: * 	nothing **/static void ipr_dump_version_data(struct ipr_ioa_cfg *ioa_cfg,				  struct ipr_driver_dump *driver_dump){	ipr_init_dump_entry_hdr(&driver_dump->version_entry.hdr);	driver_dump->version_entry.hdr.len =		sizeof(struct ipr_dump_version_entry) -		sizeof(struct ipr_dump_entry_header);	driver_dump->version_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII;	driver_dump->version_entry.hdr.id = IPR_DUMP_DRIVER_VERSION_ID;	strcpy(driver_dump->version_entry.version, IPR_DRIVER_VERSION);	driver_dump->hdr.num_entries++;}/** * ipr_dump_trace_data - Fill in the IOA trace in the dump. * @ioa_cfg:	ioa config struct * @driver_dump:	driver dump struct * * Return value: * 	nothing **/static void ipr_dump_trace_data(struct ipr_ioa_cfg *ioa_cfg,				   struct ipr_driver_dump *driver_dump){	ipr_init_dump_entry_hdr(&driver_dump->trace_entry.hdr);	driver_dump->trace_entry.hdr.len =		sizeof(struct ipr_dump_trace_entry) -		sizeof(struct ipr_dump_entry_header);	driver_dump->trace_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;	driver_dump->trace_entry.hdr.id = IPR_DUMP_TRACE_ID;	memcpy(driver_dump->trace_entry.trace, ioa_cfg->trace, IPR_TRACE_SIZE);	driver_dump->hdr.num_entries++;}/** * ipr_dump_location_data - Fill in the IOA location in the dump. * @ioa_cfg:	ioa config struct * @driver_dump:	driver dump struct * * Return value: * 	nothing **/static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg,				   struct ipr_driver_dump *driver_dump){	ipr_init_dump_entry_hdr(&driver_dump->location_entry.hdr);	driver_dump->location_entry.hdr.len =		sizeof(struct ipr_dump_location_entry) -		sizeof(struct ipr_dump_entry_header);	driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII;	driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID;	strcpy(driver_dump->location_entry.location, ioa_cfg->pdev->dev.bus_id);	driver_dump->hdr.num_entries++;}/** * ipr_get_ioa_dump - Perform a dump of the driver and adapter. * @ioa_cfg:	ioa config struct * @dump:		dump struct * * Return value: * 	nothing **/static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump){	unsigned long start_addr, sdt_word;	unsigned long lock_flags = 0;	struct ipr_driver_dump *driver_dump = &dump->driver_dump;	struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump;	u32 num_entries, start_off, end_off;	u32 bytes_to_copy, bytes_copied, rc;	struct ipr_sdt *sdt;	int i;	ENTER;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	if (ioa_cfg->sdt_state != GET_DUMP) {		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		return;	}	start_addr = readl(ioa_cfg->ioa_mailbox);	if (!ipr_sdt_is_fmt2(start_addr)) {		dev_err(&ioa_cfg->pdev->dev,			"Invalid dump table format: %lx\n", start_addr);		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		return;	}	dev_err(&ioa_cfg->pdev->dev, "Dump of IOA initiated\n");	driver_dump->hdr.eye_catcher = IPR_DUMP_EYE_CATCHER;	/* Initialize the overall dump header */	driver_dump->hdr.len = sizeof(struct ipr_driver_dump);	driver_dump->hdr.num_entries = 1;	driver_dump->hdr.first_entry_offset = sizeof(struct ipr_dump_header);	driver_dump->hdr.status = IPR_DUMP_STATUS_SUCCESS;	driver_dump->hdr.os = IPR_DUMP_OS_LINUX;	driver_dump->hdr.driver_name = IPR_DUMP_DRIVER_NAME;	ipr_dump_version_data(ioa_cfg, driver_dump);	ipr_dump_location_data(ioa_cfg, driver_dump);	ipr_dump_ioa_type_data(ioa_cfg, driver_dump);	ipr_dump_trace_data(ioa_cfg, driver_dump);	/* Update dump_header */	driver_dump->hdr.len += sizeof(struct ipr_dump_entry_header);	/* IOA Dump entry */	ipr_init_dump_entry_hdr(&ioa_dump->hdr);	ioa_dump->format = IPR_SDT_FMT2;	ioa_dump->hdr.len = 0;	ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;	ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID;	/* First entries in sdt are actually a list of dump addresses and	 lengths to gather the real dump data.  sdt represents the pointer	 to the ioa generated dump table.  Dump data will be extracted based	 on entries in this table */	sdt = &ioa_dump->sdt;	rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (u32 *)sdt,					sizeof(struct ipr_sdt) / sizeof(u32));	/* Smart Dump table is ready to use and the first entry is valid */	if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) {		dev_err(&ioa_cfg->pdev->dev,			"Dump of IOA failed. Dump table not valid: %d, %X.\n",			rc, be32_to_cpu(sdt->hdr.state));		driver_dump->hdr.status = IPR_DUMP_STATUS_FAILED;		ioa_cfg->sdt_state = DUMP_OBTAINED;		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		return;	}	num_entries = be32_to_cpu(sdt->hdr.num_entries_used);	if (num_entries > IPR_NUM_SDT_ENTRIES)		num_entries = IPR_NUM_SDT_ENTRIES;	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	for (i = 0; i < num_entries; i++) {		if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) {			driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS;			break;		}		if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) {			sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset);			start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK;			end_off = be32_to_cpu(sdt->entry[i].end_offset);			if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) {				bytes_to_copy = end_off - start_off;				if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) {					sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY;					continue;				}				/* Copy data from adapter to driver buffers */				bytes_copied = ipr_sdt_copy(ioa_cfg, sdt_word,							    bytes_to_copy);				ioa_dump->hdr.len += bytes_copied;				if (bytes_copied != bytes_to_copy) {					driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS;					break;				}			}		}	}	dev_err(&ioa_cfg->pdev->dev, "Dump of IOA completed.\n");	/* Update dump_header */	driver_dump->hdr.len += ioa_dump->hdr.len;	wmb();	ioa_cfg->sdt_state = DUMP_OBTAINED;	LEAVE;}#else#define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0)#endif/** * ipr_release_dump - Free adapter dump memory * @kref:	kref struct * * Return value: *	nothing **/static void ipr_release_dump(struct kref *kref){	struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref);	struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg;	unsigned long lock_flags = 0;	int i;	ENTER;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	ioa_cfg->dump = NULL;	ioa_cfg->sdt_state = INACTIVE;	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	for (i = 0; i < dump->ioa_dump.next_page_index; i++)		free_page((unsigned long) dump->ioa_dump.ioa_data[i]);	kfree(dump);	LEAVE;}/** * ipr_worker_thread - Worker thread * @data:		ioa config struct * * Called at task level from a work thread. This function takes care * of adding and removing device from the mid-layer as configuration * changes are detected by the adapter. * * Return value: * 	nothing **/static void ipr_worker_thread(void *data){	unsigned long lock_flags;	struct ipr_resource_entry *res;	struct scsi_device *sdev;	struct ipr_dump *dump;	struct ipr_ioa_cfg *ioa_cfg = data;	u8 bus, target, lun;	int did_work;	ENTER;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	if (ioa_cfg->sdt_state == GET_DUMP) {		dump = ioa_cfg->dump;		if (!dump) {			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);			return;		}		kref_get(&dump->kref);		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		ipr_get_ioa_dump(ioa_cfg, dump);		kref_put(&dump->kref, ipr_release_dump);		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);		if (ioa_cfg->sdt_state == DUMP_OBTAINED)			ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		return;	}restart:	do {		did_work = 0;		if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) {			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);			return;		}		list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {			if (res->del_from_ml && res->sdev) {				did_work = 1;				sdev = res->sdev;				if (!scsi_device_get(sdev)) {					res->sdev = NULL;					list_move_tail(&res->queue, &ioa_cfg->free_res_q);					spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);					scsi_remove_device(sdev);					scsi_device_put(sdev);					spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);				}				break;			}		}	} while(did_work);	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {		if (res->add_to_ml) {			bus = res->cfgte.res_addr.bus;			target = res->cfgte.res_addr.target;			lun = res->cfgte.res_addr.lun;			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);			scsi_add_device(ioa_cfg->host, bus, target, lun);

⌨️ 快捷键说明

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