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 + -
显示快捷键?