📄 ipr.c
字号:
{ "VSBPD1H U3SCSI", "XXXXXXX*XXXXXXXX", 160 }};/* * Function Prototypes */static int ipr_reset_alert(struct ipr_cmnd *);static void ipr_process_ccn(struct ipr_cmnd *);static void ipr_process_error(struct ipr_cmnd *);static void ipr_reset_ioa_job(struct ipr_cmnd *);static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *, enum ipr_shutdown_type);#ifdef CONFIG_SCSI_IPR_TRACE/** * ipr_trc_hook - Add a trace entry to the driver trace * @ipr_cmd: ipr command struct * @type: trace type * @add_data: additional data * * Return value: * none **/static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, u8 type, u32 add_data){ struct ipr_trace_entry *trace_entry; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; trace_entry = &ioa_cfg->trace[ioa_cfg->trace_index++]; trace_entry->time = jiffies; trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; trace_entry->type = type; trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command; trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff; trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; trace_entry->u.add_data = add_data;}#else#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)#endif/** * ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse * @ipr_cmd: ipr command struct * * Return value: * none **/static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd){ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr); memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); ioarcb->write_data_transfer_length = 0; ioarcb->read_data_transfer_length = 0; ioarcb->write_ioadl_len = 0; ioarcb->read_ioadl_len = 0; ioarcb->write_ioadl_addr = cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; ioasa->ioasc = 0; ioasa->residual_data_len = 0; ioasa->u.gata.status = 0; ipr_cmd->scsi_cmd = NULL; ipr_cmd->qc = NULL; ipr_cmd->sense_buffer[0] = 0; ipr_cmd->dma_use_sg = 0;}/** * ipr_init_ipr_cmnd - Initialize an IPR Cmnd block * @ipr_cmd: ipr command struct * * Return value: * none **/static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd){ ipr_reinit_ipr_cmnd(ipr_cmd); ipr_cmd->u.scratch = 0; ipr_cmd->sibling = NULL; init_timer(&ipr_cmd->timer);}/** * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block * @ioa_cfg: ioa config struct * * Return value: * pointer to ipr command struct **/staticstruct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg){ struct ipr_cmnd *ipr_cmd; ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue); list_del(&ipr_cmd->queue); ipr_init_ipr_cmnd(ipr_cmd); return ipr_cmd;}/** * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts * @ioa_cfg: ioa config struct * @clr_ints: interrupts to clear * * This function masks all interrupts on the adapter, then clears the * interrupts specified in the mask * * Return value: * none **/static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg, u32 clr_ints){ volatile u32 int_reg; /* Stop new interrupts */ ioa_cfg->allow_interrupts = 0; /* Set interrupt mask to stop all new interrupts */ writel(~0, ioa_cfg->regs.set_interrupt_mask_reg); /* Clear any pending interrupts */ writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg); int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);}/** * ipr_save_pcix_cmd_reg - Save PCI-X command register * @ioa_cfg: ioa config struct * * Return value: * 0 on success / -EIO on failure **/static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg){ int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); if (pcix_cmd_reg == 0) return 0; if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); return -EIO; } ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO; return 0;}/** * ipr_set_pcix_cmd_reg - Setup PCI-X command register * @ioa_cfg: ioa config struct * * Return value: * 0 on success / -EIO on failure **/static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg){ int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); if (pcix_cmd_reg) { if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n"); return -EIO; } } return 0;}/** * ipr_sata_eh_done - done function for aborted SATA commands * @ipr_cmd: ipr command struct * * This function is invoked for ops generated to SATA * devices which are being aborted. * * Return value: * none **/static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd){ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct ata_queued_cmd *qc = ipr_cmd->qc; struct ipr_sata_port *sata_port = qc->ap->private_data; qc->err_mask |= AC_ERR_OTHER; sata_port->ioasa.status |= ATA_BUSY; list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); ata_qc_complete(qc);}/** * ipr_scsi_eh_done - mid-layer done function for aborted ops * @ipr_cmd: ipr command struct * * This function is invoked by the interrupt handler for * ops generated by the SCSI mid-layer which are being aborted. * * Return value: * none **/static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd){ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; scsi_cmd->result |= (DID_ERROR << 16); scsi_dma_unmap(ipr_cmd->scsi_cmd); scsi_cmd->scsi_done(scsi_cmd); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);}/** * ipr_fail_all_ops - Fails all outstanding ops. * @ioa_cfg: ioa config struct * * This function fails all outstanding ops. * * Return value: * none **/static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg){ struct ipr_cmnd *ipr_cmd, *temp; ENTER; list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) { list_del(&ipr_cmd->queue); ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET); ipr_cmd->ioasa.ilid = cpu_to_be32(IPR_DRIVER_ILID); if (ipr_cmd->scsi_cmd) ipr_cmd->done = ipr_scsi_eh_done; else if (ipr_cmd->qc) ipr_cmd->done = ipr_sata_eh_done; ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); del_timer(&ipr_cmd->timer); ipr_cmd->done(ipr_cmd); } LEAVE;}/** * ipr_do_req - Send driver initiated requests. * @ipr_cmd: ipr command struct * @done: done function * @timeout_func: timeout function * @timeout: timeout value * * This function sends the specified command to the adapter with the * timeout given. The done function is invoked on command completion. * * Return value: * none **/static void ipr_do_req(struct ipr_cmnd *ipr_cmd, void (*done) (struct ipr_cmnd *), void (*timeout_func) (struct ipr_cmnd *), u32 timeout){ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); ipr_cmd->done = done; ipr_cmd->timer.data = (unsigned long) ipr_cmd; ipr_cmd->timer.expires = jiffies + timeout; ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func; add_timer(&ipr_cmd->timer); ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0); mb(); writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), ioa_cfg->regs.ioarrin_reg);}/** * ipr_internal_cmd_done - Op done function for an internally generated op. * @ipr_cmd: ipr command struct * * This function is the op done function for an internally generated, * blocking op. It simply wakes the sleeping thread. * * Return value: * none **/static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd){ if (ipr_cmd->sibling) ipr_cmd->sibling = NULL; else complete(&ipr_cmd->completion);}/** * ipr_send_blocking_cmd - Send command and sleep on its completion. * @ipr_cmd: ipr command struct * @timeout_func: function to invoke if command times out * @timeout: timeout * * Return value: * none **/static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd, void (*timeout_func) (struct ipr_cmnd *ipr_cmd), u32 timeout){ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; init_completion(&ipr_cmd->completion); ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout); spin_unlock_irq(ioa_cfg->host->host_lock); wait_for_completion(&ipr_cmd->completion); spin_lock_irq(ioa_cfg->host->host_lock);}/** * ipr_send_hcam - Send an HCAM to the adapter. * @ioa_cfg: ioa config struct * @type: HCAM type * @hostrcb: hostrcb struct * * This function will send a Host Controlled Async command to the adapter. * If HCAMs are currently not allowed to be issued to the adapter, it will * place the hostrcb on the free queue. * * Return value: * none **/static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, struct ipr_hostrcb *hostrcb){ struct ipr_cmnd *ipr_cmd; struct ipr_ioarcb *ioarcb; if (ioa_cfg->allow_cmds) { ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q); ipr_cmd->u.hostrcb = hostrcb; ioarcb = &ipr_cmd->ioarcb; ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM; ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC; ioarcb->cmd_pkt.cdb[1] = type; ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff; ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff; ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam)); ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); ipr_cmd->ioadl[0].flags_and_data_len = cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam)); ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma); if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE) ipr_cmd->done = ipr_process_ccn; else ipr_cmd->done = ipr_process_error; ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR); mb(); writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), ioa_cfg->regs.ioarrin_reg); } else { list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); }}/** * ipr_init_res_entry - Initialize a resource entry struct. * @res: resource entry struct * * Return value: * none **/static void ipr_init_res_entry(struct ipr_resource_entry *res){ res->needs_sync_complete = 0; res->in_erp = 0; res->add_to_ml = 0; res->del_from_ml = 0; res->resetting_device = 0; res->sdev = NULL; res->sata_port = NULL;}/** * ipr_handle_config_change - Handle a config change from the adapter * @ioa_cfg: ioa config struct * @hostrcb: hostrcb * * Return value: * none **/static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg, struct ipr_hostrcb *hostrcb){ struct ipr_resource_entry *res = NULL; struct ipr_config_table_entry *cfgte; u32 is_ndn = 1; cfgte = &hostrcb->hcam.u.ccn.cfgte; list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr, sizeof(cfgte->res_addr))) { is_ndn = 0; break; } } if (is_ndn) { if (list_empty(&ioa_cfg->free_res_q)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -