ipr.c

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

C
2,336
字号
 * * Return value: * 	none **/static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg,				 struct ipr_hostrcb *hostrcb){	int errors_logged, i;	struct ipr_hostrcb_device_data_entry *dev_entry;	struct ipr_hostrcb_type_03_error *error;	error = &hostrcb->hcam.u.error.u.type_03_error;	errors_logged = be32_to_cpu(error->errors_logged);	ipr_err("Device Errors Detected/Logged: %d/%d\n",		be32_to_cpu(error->errors_detected), errors_logged);	dev_entry = error->dev_entry;	for (i = 0; i < errors_logged; i++, dev_entry++) {		ipr_err_separator;		if (dev_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {			ipr_err("Device %d: missing\n", i + 1);		} else {			ipr_err("Device %d: %d:%d:%d:%d\n", i + 1,				ioa_cfg->host->host_no, dev_entry->dev_res_addr.bus,				dev_entry->dev_res_addr.target, dev_entry->dev_res_addr.lun);		}		ipr_log_vpd(&dev_entry->dev_vpids, dev_entry->dev_sn);		ipr_err("-----New Device Information-----\n");		ipr_log_vpd(&dev_entry->new_dev_vpids, dev_entry->new_dev_sn);		ipr_err("Cache Directory Card Information:\n");		ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpids,			    dev_entry->ioa_last_with_dev_sn);		ipr_err("Adapter Card Information:\n");		ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpids,			    dev_entry->cfc_last_with_dev_sn);		ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n",			be32_to_cpu(dev_entry->ioa_data[0]),			be32_to_cpu(dev_entry->ioa_data[1]),			be32_to_cpu(dev_entry->ioa_data[2]),			be32_to_cpu(dev_entry->ioa_data[3]),			be32_to_cpu(dev_entry->ioa_data[4]));	}}/** * ipr_log_array_error - Log an array configuration error. * @ioa_cfg:	ioa config struct * @hostrcb:	hostrcb struct * * Return value: * 	none **/static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg,				struct ipr_hostrcb *hostrcb){	int i;	struct ipr_hostrcb_type_04_error *error;	struct ipr_hostrcb_array_data_entry *array_entry;	u8 zero_sn[IPR_SERIAL_NUM_LEN];	memset(zero_sn, '0', IPR_SERIAL_NUM_LEN);	error = &hostrcb->hcam.u.error.u.type_04_error;	ipr_err_separator;	ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n",		error->protection_level,		ioa_cfg->host->host_no,		error->last_func_vset_res_addr.bus,		error->last_func_vset_res_addr.target,		error->last_func_vset_res_addr.lun);	ipr_err_separator;	array_entry = error->array_member;	for (i = 0; i < 18; i++) {		if (!memcmp(array_entry->serial_num, zero_sn, IPR_SERIAL_NUM_LEN))			continue;		if (error->exposed_mode_adn == i) {			ipr_err("Exposed Array Member %d:\n", i);		} else {			ipr_err("Array Member %d:\n", i);		}		ipr_log_vpd(&array_entry->vpids, array_entry->serial_num);		if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {			ipr_err("Current Location: unknown\n");		} else {			ipr_err("Current Location: %d:%d:%d:%d\n",				ioa_cfg->host->host_no,				array_entry->dev_res_addr.bus,				array_entry->dev_res_addr.target,				array_entry->dev_res_addr.lun);		}		if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {			ipr_err("Expected Location: unknown\n");		} else {			ipr_err("Expected Location: %d:%d:%d:%d\n",				ioa_cfg->host->host_no,				array_entry->expected_dev_res_addr.bus,				array_entry->expected_dev_res_addr.target,				array_entry->expected_dev_res_addr.lun);		}		ipr_err_separator;		if (i == 9)			array_entry = error->array_member2;		else			array_entry++;	}}/** * ipr_log_generic_error - Log an adapter error. * @ioa_cfg:	ioa config struct * @hostrcb:	hostrcb struct * * Return value: * 	none **/static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,				  struct ipr_hostrcb *hostrcb){	int i;	int ioa_data_len = be32_to_cpu(hostrcb->hcam.length);	if (ioa_data_len == 0)		return;	ipr_err("IOA Error Data:\n");	ipr_err("Offset    0 1 2 3  4 5 6 7  8 9 A B  C D E F\n");	for (i = 0; i < ioa_data_len / 4; i += 4) {		ipr_err("%08X: %08X %08X %08X %08X\n", i*4,			be32_to_cpu(hostrcb->hcam.u.raw.data[i]),			be32_to_cpu(hostrcb->hcam.u.raw.data[i+1]),			be32_to_cpu(hostrcb->hcam.u.raw.data[i+2]),			be32_to_cpu(hostrcb->hcam.u.raw.data[i+3]));	}}/** * ipr_get_error - Find the specfied IOASC in the ipr_error_table. * @ioasc:	IOASC * * This function will return the index of into the ipr_error_table * for the specified IOASC. If the IOASC is not in the table, * 0 will be returned, which points to the entry used for unknown errors. * * Return value: * 	index into the ipr_error_table **/static u32 ipr_get_error(u32 ioasc){	int i;	for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++)		if (ipr_error_table[i].ioasc == ioasc)			return i;	return 0;}/** * ipr_handle_log_data - Log an adapter error. * @ioa_cfg:	ioa config struct * @hostrcb:	hostrcb struct * * This function logs an adapter error to the system. * * Return value: * 	none **/static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,				struct ipr_hostrcb *hostrcb){	u32 ioasc;	int error_index;	if (hostrcb->hcam.notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY)		return;	if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST)		dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n");	ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);	if (ioasc == IPR_IOASC_BUS_WAS_RESET ||	    ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) {		/* Tell the midlayer we had a bus reset so it will handle the UA properly */		scsi_report_bus_reset(ioa_cfg->host,				      hostrcb->hcam.u.error.failing_dev_res_addr.bus);	}	error_index = ipr_get_error(ioasc);	if (!ipr_error_table[error_index].log_hcam)		return;	if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {		ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,			    "%s\n", ipr_error_table[error_index].error);	} else {		dev_err(&ioa_cfg->pdev->dev, "%s\n",			ipr_error_table[error_index].error);	}	/* Set indication we have logged an error */	ioa_cfg->errors_logged++;	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)		return;	switch (hostrcb->hcam.overlay_id) {	case IPR_HOST_RCB_OVERLAY_ID_1:		ipr_log_generic_error(ioa_cfg, hostrcb);		break;	case IPR_HOST_RCB_OVERLAY_ID_2:		ipr_log_cache_error(ioa_cfg, hostrcb);		break;	case IPR_HOST_RCB_OVERLAY_ID_3:		ipr_log_config_error(ioa_cfg, hostrcb);		break;	case IPR_HOST_RCB_OVERLAY_ID_4:	case IPR_HOST_RCB_OVERLAY_ID_6:		ipr_log_array_error(ioa_cfg, hostrcb);		break;	case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:		ipr_log_generic_error(ioa_cfg, hostrcb);		break;	default:		dev_err(&ioa_cfg->pdev->dev,			"Unknown error received. Overlay ID: %d\n",			hostrcb->hcam.overlay_id);		break;	}}/** * ipr_process_error - Op done function for an adapter error log. * @ipr_cmd:	ipr command struct * * This function is the op done function for an error log host * controlled async from the adapter. It will log the error and * send the HCAM back to the adapter. * * Return value: * 	none **/static void ipr_process_error(struct ipr_cmnd *ipr_cmd){	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);	list_del(&hostrcb->queue);	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);	if (!ioasc) {		ipr_handle_log_data(ioa_cfg, hostrcb);	} else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {		dev_err(&ioa_cfg->pdev->dev,			"Host RCB failed with IOASC: 0x%08X\n", ioasc);	}	ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);}/** * 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_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,				      u32 *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");

⌨️ 快捷键说明

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