📄 ipr.c
字号:
/** * 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 + -