ql4_os.c
来自「linux 内核源代码」· C语言 代码 · 共 1,732 行 · 第 1/4 页
C
1,732 行
* that the command has been processed. * * Remarks: * This routine is invoked by Linux to send a SCSI command to the driver. * The mid-level driver tries to ensure that queuecommand never gets * invoked concurrently with itself or the interrupt handler (although * the interrupt handler may call this routine as part of request- * completion handling). Unfortunely, it sometimes calls the scheduler * in interrupt context which is a big NO! NO!. **/static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){ struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; struct srb *srb; int rval; if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { cmd->result = DID_NO_CONNECT << 16; goto qc_fail_command; } goto qc_host_busy; } if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) goto qc_host_busy; spin_unlock_irq(ha->host->host_lock); srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done); if (!srb) goto qc_host_busy_lock; rval = qla4xxx_send_command_to_isp(ha, srb); if (rval != QLA_SUCCESS) goto qc_host_busy_free_sp; spin_lock_irq(ha->host->host_lock); return 0;qc_host_busy_free_sp: qla4xxx_srb_free_dma(ha, srb); mempool_free(srb, ha->srb_mempool);qc_host_busy_lock: spin_lock_irq(ha->host->host_lock);qc_host_busy: return SCSI_MLQUEUE_HOST_BUSY;qc_fail_command: done(cmd); return 0;}/** * qla4xxx_mem_free - frees memory allocated to adapter * @ha: Pointer to host adapter structure. * * Frees memory previously allocated by qla4xxx_mem_alloc **/static void qla4xxx_mem_free(struct scsi_qla_host *ha){ if (ha->queues) dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, ha->queues_dma); ha->queues_len = 0; ha->queues = NULL; ha->queues_dma = 0; ha->request_ring = NULL; ha->request_dma = 0; ha->response_ring = NULL; ha->response_dma = 0; ha->shadow_regs = NULL; ha->shadow_regs_dma = 0; /* Free srb pool. */ if (ha->srb_mempool) mempool_destroy(ha->srb_mempool); ha->srb_mempool = NULL; /* release io space registers */ if (ha->reg) iounmap(ha->reg); pci_release_regions(ha->pdev);}/** * qla4xxx_mem_alloc - allocates memory for use by adapter. * @ha: Pointer to host adapter structure * * Allocates DMA memory for request and response queues. Also allocates memory * for srbs. **/static int qla4xxx_mem_alloc(struct scsi_qla_host *ha){ unsigned long align; /* Allocate contiguous block of DMA memory for queues. */ ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + sizeof(struct shadow_regs) + MEM_ALIGN_VALUE + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, &ha->queues_dma, GFP_KERNEL); if (ha->queues == NULL) { dev_warn(&ha->pdev->dev, "Memory Allocation failed - queues.\n"); goto mem_alloc_error_exit; } memset(ha->queues, 0, ha->queues_len); /* * As per RISC alignment requirements -- the bus-address must be a * multiple of the request-ring size (in bytes). */ align = 0; if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)); /* Update request and response queue pointers. */ ha->request_dma = ha->queues_dma + align; ha->request_ring = (struct queue_entry *) (ha->queues + align); ha->response_dma = ha->queues_dma + align + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); ha->response_ring = (struct queue_entry *) (ha->queues + align + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE)); ha->shadow_regs_dma = ha->queues_dma + align + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE)); /* Allocate memory for srb pool. */ ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, mempool_free_slab, srb_cachep); if (ha->srb_mempool == NULL) { dev_warn(&ha->pdev->dev, "Memory Allocation failed - SRB Pool.\n"); goto mem_alloc_error_exit; } return QLA_SUCCESS;mem_alloc_error_exit: qla4xxx_mem_free(ha); return QLA_ERROR;}/** * qla4xxx_timer - checks every second for work to do. * @ha: Pointer to host adapter structure. **/static void qla4xxx_timer(struct scsi_qla_host *ha){ struct ddb_entry *ddb_entry, *dtemp; int start_dpc = 0; /* Search for relogin's to time-out and port down retry. */ list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { /* Count down time between sending relogins */ if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->retry_relogin_timer) != INVALID_ENTRY) { if (atomic_read(&ddb_entry->retry_relogin_timer) == 0) { atomic_set(&ddb_entry-> retry_relogin_timer, INVALID_ENTRY); set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); set_bit(DF_RELOGIN, &ddb_entry->flags); DEBUG2(printk("scsi%ld: %s: index [%d]" " login device\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); } else atomic_dec(&ddb_entry-> retry_relogin_timer); } } /* Wait for relogin to timeout */ if (atomic_read(&ddb_entry->relogin_timer) && (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { /* * If the relogin times out and the device is * still NOT ONLINE then try and relogin again. */ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE && ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED) { /* Reset retry relogin timer */ atomic_inc(&ddb_entry->relogin_retry_count); DEBUG2(printk("scsi%ld: index[%d] relogin" " timed out-retrying" " relogin (%d)\n", ha->host_no, ddb_entry->fw_ddb_index, atomic_read(&ddb_entry-> relogin_retry_count)) ); start_dpc++; DEBUG(printk("scsi%ld:%d:%d: index [%d] " "initate relogin after" " %d seconds\n", ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index, ddb_entry->default_time2wait + 4) ); atomic_set(&ddb_entry->retry_relogin_timer, ddb_entry->default_time2wait + 4); } } } /* Check for heartbeat interval. */ if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && ha->heartbeat_interval != 0) { ha->seconds_since_last_heartbeat++; if (ha->seconds_since_last_heartbeat > ha->heartbeat_interval + 2) set_bit(DPC_RESET_HA, &ha->dpc_flags); } /* Wakeup the dpc routine for this adapter, if needed. */ if ((start_dpc || test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || test_bit(DPC_AEN, &ha->dpc_flags)) && ha->dpc_thread) { DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" " - dpc flags = 0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); queue_work(ha->dpc_thread, &ha->dpc_work); } /* Reschedule timer thread to call us back in one second */ mod_timer(&ha->timer, jiffies + HZ); DEBUG2(ha->seconds_since_last_intr++);}/** * qla4xxx_cmd_wait - waits for all outstanding commands to complete * @ha: Pointer to host adapter structure. * * This routine stalls the driver until all outstanding commands are returned. * Caller must release the Hardware Lock prior to calling this routine. **/static int qla4xxx_cmd_wait(struct scsi_qla_host *ha){ uint32_t index = 0; int stat = QLA_SUCCESS; unsigned long flags; struct scsi_cmnd *cmd; int wait_cnt = WAIT_CMD_TOV; /* * Initialized for 30 seconds as we * expect all commands to retuned * ASAP. */ while (wait_cnt) { spin_lock_irqsave(&ha->hardware_lock, flags); /* Find a command that hasn't completed. */ for (index = 0; index < ha->host->can_queue; index++) { cmd = scsi_host_find_tag(ha->host, index); if (cmd != NULL) break; } spin_unlock_irqrestore(&ha->hardware_lock, flags); /* If No Commands are pending, wait is complete */ if (index == ha->host->can_queue) { break; } /* If we timed out on waiting for commands to come back * return ERROR. */ wait_cnt--; if (wait_cnt == 0) stat = QLA_ERROR; else { msleep(1000); } } /* End of While (wait_cnt) */ return stat;}void qla4xxx_hw_reset(struct scsi_qla_host *ha){ uint32_t ctrl_status; unsigned long flags = 0; DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); spin_lock_irqsave(&ha->hardware_lock, flags); /* * If the SCSI Reset Interrupt bit is set, clear it. * Otherwise, the Soft Reset won't work. */ ctrl_status = readw(&ha->reg->ctrl_status); if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); /* Issue Soft Reset */ writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags);}/** * qla4xxx_soft_reset - performs soft reset. * @ha: Pointer to host adapter structure. **/int qla4xxx_soft_reset(struct scsi_qla_host *ha){ uint32_t max_wait_time; unsigned long flags = 0; int status = QLA_ERROR; uint32_t ctrl_status; qla4xxx_hw_reset(ha); /* Wait until the Network Reset Intr bit is cleared */ max_wait_time = RESET_INTR_TOV; do { spin_lock_irqsave(&ha->hardware_lock, flags); ctrl_status = readw(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if ((ctrl_status & CSR_NET_RESET_INTR) == 0) break; msleep(1000); } while ((--max_wait_time)); if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { DEBUG2(printk(KERN_WARNING "scsi%ld: Network Reset Intr not cleared by " "Network function, clearing it now!\n", ha->host_no)); spin_lock_irqsave(&ha->hardware_lock, flags); writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); } /* Wait until the firmware tells us the Soft Reset is done */ max_wait_time = SOFT_RESET_TOV; do { spin_lock_irqsave(&ha->hardware_lock, flags); ctrl_status = readw(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if ((ctrl_status & CSR_SOFT_RESET) == 0) { status = QLA_SUCCESS; break; } msleep(1000); } while ((--max_wait_time)); /* * Also, make sure that the SCSI Reset Interrupt bit has been cleared * after the soft reset has taken place. */ spin_lock_irqsave(&ha->hardware_lock, flags); ctrl_status = readw(&ha->reg->ctrl_status); if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); } spin_unlock_irqrestore(&ha->hardware_lock, flags); /* If soft reset fails then most probably the bios on other * function is also enabled. * Since the initialization is sequential the other fn * wont be able to acknowledge the soft reset. * Issue a force soft reset to workaround this scenario. */ if (max_wait_time == 0) { /* Issue Force Soft Reset */ spin_lock_irqsave(&ha->hardware_lock, flags); writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait until the firmware tells us the Soft Reset is done */ max_wait_time = SOFT_RESET_TOV; do { spin_lock_irqsave(&ha->hardware_lock, flags); ctrl_status = readw(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { status = QLA_SUCCESS; break; } msleep(1000); } while ((--max_wait_time)); } return status;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?