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

📄 ipr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/** * ipr_timeout -  An internally generated op has timed out. * @ipr_cmd:	ipr command struct * * This function blocks host requests and initiates an * adapter reset. * * Return value: * 	none **/static void ipr_timeout(struct ipr_cmnd *ipr_cmd){	unsigned long lock_flags = 0;	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	ENTER;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	ioa_cfg->errors_logged++;	dev_err(&ioa_cfg->pdev->dev,		"Adapter being reset due to command timeout.\n");	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)		ioa_cfg->sdt_state = GET_DUMP;	if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd)		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	LEAVE;}/** * ipr_oper_timeout -  Adapter timed out transitioning to operational * @ipr_cmd:	ipr command struct * * This function blocks host requests and initiates an * adapter reset. * * Return value: * 	none **/static void ipr_oper_timeout(struct ipr_cmnd *ipr_cmd){	unsigned long lock_flags = 0;	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	ENTER;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	ioa_cfg->errors_logged++;	dev_err(&ioa_cfg->pdev->dev,		"Adapter timed out transitioning to operational.\n");	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)		ioa_cfg->sdt_state = GET_DUMP;	if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) {		if (ipr_fastfail)			ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES;		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);	}	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	LEAVE;}/** * ipr_reset_reload - Reset/Reload the IOA * @ioa_cfg:		ioa config struct * @shutdown_type:	shutdown type * * This function resets the adapter and re-initializes it. * This function assumes that all new host commands have been stopped. * Return value: * 	SUCCESS / FAILED **/static int ipr_reset_reload(struct ipr_ioa_cfg *ioa_cfg,			    enum ipr_shutdown_type shutdown_type){	if (!ioa_cfg->in_reset_reload)		ipr_initiate_ioa_reset(ioa_cfg, shutdown_type);	spin_unlock_irq(ioa_cfg->host->host_lock);	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);	spin_lock_irq(ioa_cfg->host->host_lock);	/* If we got hit with a host reset while we were already resetting	 the adapter for some reason, and the reset failed. */	if (ioa_cfg->ioa_is_dead) {		ipr_trace;		return FAILED;	}	return SUCCESS;}/** * ipr_find_ses_entry - Find matching SES in SES table * @res:	resource entry struct of SES * * Return value: * 	pointer to SES table entry / NULL on failure **/static const struct ipr_ses_table_entry *ipr_find_ses_entry(struct ipr_resource_entry *res){	int i, j, matches;	const struct ipr_ses_table_entry *ste = ipr_ses_table;	for (i = 0; i < ARRAY_SIZE(ipr_ses_table); i++, ste++) {		for (j = 0, matches = 0; j < IPR_PROD_ID_LEN; j++) {			if (ste->compare_product_id_byte[j] == 'X') {				if (res->cfgte.std_inq_data.vpids.product_id[j] == ste->product_id[j])					matches++;				else					break;			} else				matches++;		}		if (matches == IPR_PROD_ID_LEN)			return ste;	}	return NULL;}/** * ipr_get_max_scsi_speed - Determine max SCSI speed for a given bus * @ioa_cfg:	ioa config struct * @bus:		SCSI bus * @bus_width:	bus width * * Return value: *	SCSI bus speed in units of 100KHz, 1600 is 160 MHz *	For a 2-byte wide SCSI bus, the maximum transfer speed is *	twice the maximum transfer rate (e.g. for a wide enabled bus, *	max 160MHz = max 320MB/sec). **/static u32 ipr_get_max_scsi_speed(struct ipr_ioa_cfg *ioa_cfg, u8 bus, u8 bus_width){	struct ipr_resource_entry *res;	const struct ipr_ses_table_entry *ste;	u32 max_xfer_rate = IPR_MAX_SCSI_RATE(bus_width);	/* Loop through each config table entry in the config table buffer */	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {		if (!(IPR_IS_SES_DEVICE(res->cfgte.std_inq_data)))			continue;		if (bus != res->cfgte.res_addr.bus)			continue;		if (!(ste = ipr_find_ses_entry(res)))			continue;		max_xfer_rate = (ste->max_bus_speed_limit * 10) / (bus_width / 8);	}	return max_xfer_rate;}/** * ipr_wait_iodbg_ack - Wait for an IODEBUG ACK from the IOA * @ioa_cfg:		ioa config struct * @max_delay:		max delay in micro-seconds to wait * * Waits for an IODEBUG ACK from the IOA, doing busy looping. * * Return value: * 	0 on success / other on failure **/static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay){	volatile u32 pcii_reg;	int delay = 1;	/* Read interrupt reg until IOA signals IO Debug Acknowledge */	while (delay < max_delay) {		pcii_reg = readl(ioa_cfg->regs.sense_interrupt_reg);		if (pcii_reg & IPR_PCII_IO_DEBUG_ACKNOWLEDGE)			return 0;		/* udelay cannot be used if delay is more than a few milliseconds */		if ((delay / 1000) > MAX_UDELAY_MS)			mdelay(delay / 1000);		else			udelay(delay);		delay += delay;	}	return -EIO;}/** * ipr_get_ldump_data_section - Dump IOA memory * @ioa_cfg:			ioa config struct * @start_addr:			adapter address to dump * @dest:				destination kernel buffer * @length_in_words:	length to dump in 4 byte words * * Return value: * 	0 on success / -EIO on failure **/static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,				      u32 start_addr,				      __be32 *dest, u32 length_in_words){	volatile u32 temp_pcii_reg;	int i, delay = 0;	/* Write IOA interrupt reg starting LDUMP state  */	writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT),	       ioa_cfg->regs.set_uproc_interrupt_reg);	/* Wait for IO debug acknowledge */	if (ipr_wait_iodbg_ack(ioa_cfg,			       IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC)) {		dev_err(&ioa_cfg->pdev->dev,			"IOA dump long data transfer timeout\n");		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;	__be32 *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 = (__be32 *)__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);	d

⌨️ 快捷键说明

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