ql4_os.c
来自「linux 内核源代码」· C语言 代码 · 共 1,732 行 · 第 1/4 页
C
1,732 行
ret = -ENODEV; goto probe_failed; } INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); ret = request_irq(pdev->irq, qla4xxx_intr_handler, IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); if (ret) { dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" " already in use.\n", pdev->irq); goto probe_failed; } set_bit(AF_IRQ_ATTACHED, &ha->flags); host->irq = pdev->irq; DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq)); qla4xxx_enable_intrs(ha); /* Start timer thread. */ qla4xxx_start_timer(ha, qla4xxx_timer, 1); set_bit(AF_INIT_DONE, &ha->flags); pci_set_drvdata(pdev, ha); ret = scsi_add_host(host, &pdev->dev); if (ret) goto probe_failed; /* Update transport device information for all devices. */ list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) if (qla4xxx_add_sess(ddb_entry)) goto remove_host; } printk(KERN_INFO " QLogic iSCSI HBA Driver version: %s\n" " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); return 0;remove_host: qla4xxx_free_ddb_list(ha); scsi_remove_host(host);probe_failed: qla4xxx_free_adapter(ha); scsi_host_put(ha->host);probe_disable_device: pci_disable_device(pdev); return ret;}/** * qla4xxx_remove_adapter - calback function to remove adapter. * @pci_dev: PCI device pointer **/static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev){ struct scsi_qla_host *ha; ha = pci_get_drvdata(pdev); qla4xxx_disable_intrs(ha); while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) ssleep(1); /* remove devs from iscsi_sessions to scsi_devices */ qla4xxx_free_ddb_list(ha); scsi_remove_host(ha->host); qla4xxx_free_adapter(ha); scsi_host_put(ha->host); pci_set_drvdata(pdev, NULL);}/** * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context * * At exit, the @ha's flags.enable_64bit_addressing set to indicated * supported addressing method. */static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha){ int retval; /* Update our PCI device dma_mask for full 64 bit mask */ if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) { if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { dev_dbg(&ha->pdev->dev, "Failed to set 64 bit PCI consistent mask; " "using 32 bit.\n"); retval = pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK); } } else retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);}static int qla4xxx_slave_alloc(struct scsi_device *sdev){ struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); struct ddb_entry *ddb = sess->dd_data; sdev->hostdata = ddb; sdev->tagged_supported = 1; scsi_activate_tcq(sdev, sdev->host->can_queue); return 0;}static int qla4xxx_slave_configure(struct scsi_device *sdev){ sdev->tagged_supported = 1; return 0;}static void qla4xxx_slave_destroy(struct scsi_device *sdev){ scsi_deactivate_tcq(sdev, 1);}/** * qla4xxx_del_from_active_array - returns an active srb * @ha: Pointer to host adapter structure. * @index: index into to the active_array * * This routine removes and returns the srb at the specified index **/struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index){ struct srb *srb = NULL; struct scsi_cmnd *cmd; if (!(cmd = scsi_host_find_tag(ha->host, index))) return srb; if (!(srb = (struct srb *)cmd->host_scribble)) return srb; /* update counters */ if (srb->flags & SRB_DMA_VALID) { ha->req_q_count += srb->iocb_cnt; ha->iocb_cnt -= srb->iocb_cnt; if (srb->cmd) srb->cmd->host_scribble = NULL; } return srb;}/** * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware * @ha: actual ha whose done queue will contain the comd returned by firmware. * @cmd: Scsi Command to wait on. * * This routine waits for the command to be returned by the Firmware * for some max time. **/static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, struct scsi_cmnd *cmd){ int done = 0; struct srb *rp; uint32_t max_wait_time = EH_WAIT_CMD_TOV; do { /* Checking to see if its returned to OS */ rp = (struct srb *) cmd->SCp.ptr; if (rp == NULL) { done++; break; } msleep(2000); } while (max_wait_time--); return done;}/** * qla4xxx_wait_for_hba_online - waits for HBA to come online * @ha: Pointer to host adapter structure **/static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha){ unsigned long wait_online; wait_online = jiffies + (30 * HZ); while (time_before(jiffies, wait_online)) { if (adapter_up(ha)) return QLA_SUCCESS; else if (ha->retry_reset_ha_cnt == 0) return QLA_ERROR; msleep(2000); } return QLA_ERROR;}/** * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. * @ha: pointer to to HBA * @t: target id * @l: lun id * * This function waits for all outstanding commands to a lun to complete. It * returns 0 if all pending commands are returned and 1 otherwise. **/static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, int t, int l){ int cnt; int status = 0; struct scsi_cmnd *cmd; /* * Waiting for all commands for the designated target in the active * array */ for (cnt = 0; cnt < ha->host->can_queue; cnt++) { cmd = scsi_host_find_tag(ha->host, cnt); if (cmd && cmd->device->id == t && cmd->device->lun == l) { if (!qla4xxx_eh_wait_on_command(ha, cmd)) { status++; break; } } } return status;}/** * qla4xxx_eh_device_reset - callback for target reset. * @cmd: Pointer to Linux's SCSI command structure * * This routine is called by the Linux OS to reset all luns on the * specified target. **/static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd){ struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; struct srb *sp; int ret = FAILED, stat; sp = (struct srb *) cmd->SCp.ptr; if (!sp || !ddb_entry) return ret; dev_info(&ha->pdev->dev, "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); DEBUG2(printk(KERN_INFO "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat); goto eh_dev_reset_done; } /* Send marker. */ ha->marker_needed = 1; /* * If we are coming down the EH path, wait for all commands to complete * for the device. */ if (cmd->device->host->shost_state == SHOST_RECOVERY) { if (qla4xxx_eh_wait_for_active_target_commands(ha, cmd->device->id, cmd->device->lun)){ dev_info(&ha->pdev->dev, "DEVICE RESET FAILED - waiting for " "commands.\n"); goto eh_dev_reset_done; } } dev_info(&ha->pdev->dev, "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); ret = SUCCESS;eh_dev_reset_done: return ret;}/** * qla4xxx_eh_host_reset - kernel callback * @cmd: Pointer to Linux's SCSI command structure * * This routine is invoked by the Linux kernel to perform fatal error * recovery on the specified adapter. **/static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd){ int return_status = FAILED; struct scsi_qla_host *ha; ha = (struct scsi_qla_host *) cmd->device->host->hostdata; dev_info(&ha->pdev->dev, "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " "DEAD.\n", ha->host_no, cmd->device->channel, __func__)); return FAILED; } if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) { return_status = SUCCESS; } dev_info(&ha->pdev->dev, "HOST RESET %s.\n", return_status == FAILED ? "FAILED" : "SUCCEDED"); return return_status;}static struct pci_device_id qla4xxx_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_QLOGIC, .device = PCI_DEVICE_ID_QLOGIC_ISP4010, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { .vendor = PCI_VENDOR_ID_QLOGIC, .device = PCI_DEVICE_ID_QLOGIC_ISP4022, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { .vendor = PCI_VENDOR_ID_QLOGIC, .device = PCI_DEVICE_ID_QLOGIC_ISP4032, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, {0, 0},};MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);static struct pci_driver qla4xxx_pci_driver = { .name = DRIVER_NAME, .id_table = qla4xxx_pci_tbl, .probe = qla4xxx_probe_adapter, .remove = qla4xxx_remove_adapter,};static int __init qla4xxx_module_init(void){ int ret; /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, SLAB_HWCACHE_ALIGN, NULL); if (srb_cachep == NULL) { printk(KERN_ERR "%s: Unable to allocate SRB cache..." "Failing load!\n", DRIVER_NAME); ret = -ENOMEM; goto no_srp_cache; } /* Derive version string. */ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); if (ql4xextended_error_logging) strcat(qla4xxx_version_str, "-debug"); qla4xxx_scsi_transport = iscsi_register_transport(&qla4xxx_iscsi_transport); if (!qla4xxx_scsi_transport){ ret = -ENODEV; goto release_srb_cache; } ret = pci_register_driver(&qla4xxx_pci_driver); if (ret) goto unregister_transport; printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); return 0;unregister_transport: iscsi_unregister_transport(&qla4xxx_iscsi_transport);release_srb_cache: kmem_cache_destroy(srb_cachep);no_srp_cache: return ret;}static void __exit qla4xxx_module_exit(void){ ql4_mod_unload = 1; pci_unregister_driver(&qla4xxx_pci_driver); iscsi_unregister_transport(&qla4xxx_iscsi_transport); kmem_cache_destroy(srb_cachep);}module_init(qla4xxx_module_init);module_exit(qla4xxx_module_exit);MODULE_AUTHOR("QLogic Corporation");MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");MODULE_LICENSE("GPL");MODULE_VERSION(QLA4XXX_DRIVER_VERSION);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?