ql4_init.c
来自「linux 内核源代码」· C语言 代码 · 共 1,349 行 · 第 1/3 页
C
1,349 行
* qla4xxx_alloc_ddb - allocate device database entry * @ha: Pointer to host adapter structure. * @fw_ddb_index: Firmware's device database index * * This routine allocates a ddb_entry, ititializes some values, and * inserts it into the ddb list. **/static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, uint32_t fw_ddb_index){ struct ddb_entry *ddb_entry; DEBUG2(printk("scsi%ld: %s: fw_ddb_index [%d]\n", ha->host_no, __func__, fw_ddb_index)); ddb_entry = qla4xxx_alloc_sess(ha); if (ddb_entry == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " "to add fw_ddb_index [%d]\n", ha->host_no, __func__, fw_ddb_index)); return ddb_entry; } ddb_entry->fw_ddb_index = fw_ddb_index; atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count); atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); list_add_tail(&ddb_entry->list, &ha->ddb_list); ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ha->tot_ddbs++; return ddb_entry;}/** * qla4xxx_configure_ddbs - builds driver ddb list * @ha: Pointer to host adapter structure. * * This routine searches for all valid firmware ddb entries and builds * an internal ddb list. Ddbs that are considered valid are those with * a device state of SESSION_ACTIVE. **/static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha){ int status = QLA_SUCCESS; uint32_t fw_ddb_index = 0; uint32_t next_fw_ddb_index = 0; uint32_t ddb_state; uint32_t conn_err, err_code; struct ddb_entry *ddb_entry; uint32_t new_tgt; dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index = next_fw_ddb_index) { /* First, let's see if a device exists here */ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, &next_fw_ddb_index, &ddb_state, &conn_err, NULL, NULL) == QLA_ERROR) { DEBUG2(printk("scsi%ld: %s: get_ddb_entry, " "fw_ddb_index %d failed", ha->host_no, __func__, fw_ddb_index)); return QLA_ERROR; } DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, " "next_fw_ddb_index=%d.\n", ha->host_no, __func__, fw_ddb_index, ddb_state, next_fw_ddb_index)); /* Issue relogin, if necessary. */ if (ddb_state == DDB_DS_SESSION_FAILED || ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) { /* Try and login to device */ DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n", ha->host_no, __func__, fw_ddb_index)); err_code = ((conn_err & 0x00ff0000) >> 16); if (err_code == 0x1c || err_code == 0x06) { DEBUG2(printk("scsi%ld: %s send target " "completed " "or access denied failure\n", ha->host_no, __func__)); } else { qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0); if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, &next_fw_ddb_index, &ddb_state, &conn_err, NULL, NULL) == QLA_ERROR) { DEBUG2(printk("scsi%ld: %s:" "get_ddb_entry %d failed\n", ha->host_no, __func__, fw_ddb_index)); return QLA_ERROR; } } } if (ddb_state != DDB_DS_SESSION_ACTIVE) goto next_one; /* * if fw_ddb with session active state found, * add to ddb_list */ DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n", ha->host_no, __func__, fw_ddb_index)); /* Add DDB to internal our ddb list. */ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt); if (ddb_entry == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " "for device at fw_ddb_index %d\n", ha->host_no, __func__, fw_ddb_index)); return QLA_ERROR; } /* Fill in the device structure */ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == QLA_ERROR) { ha->fw_ddb_index_map[fw_ddb_index] = (struct ddb_entry *)INVALID_ENTRY; DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed " "for fw_ddb_index %d.\n", ha->host_no, __func__, fw_ddb_index)); return QLA_ERROR; }next_one: /* We know we've reached the last device when * next_fw_ddb_index is 0 */ if (next_fw_ddb_index == 0) break; } dev_info(&ha->pdev->dev, "DDB list done..\n"); return status;}struct qla4_relog_scan { int halt_wait; uint32_t conn_err; uint32_t err_code; uint32_t fw_ddb_index; uint32_t next_fw_ddb_index; uint32_t fw_ddb_device_state;};static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs){ struct ddb_entry *ddb_entry; /* * Don't want to do a relogin if connection * error is 0x1c. */ rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16); if (rs->err_code == 0x1c || rs->err_code == 0x06) { DEBUG2(printk( "scsi%ld: %s send target" " completed or " "access denied failure\n", ha->host_no, __func__)); } else { /* We either have a device that is in * the process of relogging in or a * device that is waiting to be * relogged in */ rs->halt_wait = 0; ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, rs->fw_ddb_index); if (ddb_entry == NULL) return QLA_ERROR; if (ddb_entry->dev_scan_wait_to_start_relogin != 0 && time_after_eq(jiffies, ddb_entry-> dev_scan_wait_to_start_relogin)) { ddb_entry->dev_scan_wait_to_start_relogin = 0; qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0); } } return QLA_SUCCESS;}static int qla4_scan_for_relogin(struct scsi_qla_host *ha, struct qla4_relog_scan *rs){ int error; /* scan for relogins * ----------------- */ for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES; rs->fw_ddb_index = rs->next_fw_ddb_index) { if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0, NULL, &rs->next_fw_ddb_index, &rs->fw_ddb_device_state, &rs->conn_err, NULL, NULL) == QLA_ERROR) return QLA_ERROR; if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS) rs->halt_wait = 0; if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED || rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) { error = qla4_test_rdy(ha, rs); if (error) return error; } /* We know we've reached the last device when * next_fw_ddb_index is 0 */ if (rs->next_fw_ddb_index == 0) break; } return QLA_SUCCESS;}/** * qla4xxx_devices_ready - wait for target devices to be logged in * @ha: pointer to adapter structure * * This routine waits up to ql4xdiscoverywait seconds * F/W database during driver load time. **/static int qla4xxx_devices_ready(struct scsi_qla_host *ha){ int error; unsigned long discovery_wtime; struct qla4_relog_scan rs; discovery_wtime = jiffies + (ql4xdiscoverywait * HZ); DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait)); do { /* poll for AEN. */ qla4xxx_get_firmware_state(ha); if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) { /* Set time-between-relogin timer */ qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS); } /* if no relogins active or needed, halt discvery wait */ rs.halt_wait = 1; error = qla4_scan_for_relogin(ha, &rs); if (rs.halt_wait) { DEBUG2(printk("scsi%ld: %s: Delay halted. Devices " "Ready.\n", ha->host_no, __func__)); return QLA_SUCCESS; } msleep(2000); } while (!time_after_eq(jiffies, discovery_wtime)); DEBUG3(qla4xxx_get_conn_event_log(ha)); return QLA_SUCCESS;}static void qla4xxx_flush_AENS(struct scsi_qla_host *ha){ unsigned long wtime; /* Flush the 0x8014 AEN from the firmware as a result of * Auto connect. We are basically doing get_firmware_ddb() * to determine whether we need to log back in or not. * Trying to do a set ddb before we have processed 0x8014 * will result in another set_ddb() for the same ddb. In other * words there will be stale entries in the aen_q. */ wtime = jiffies + (2 * HZ); do { if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) if (ha->firmware_state & (BIT_2 | BIT_0)) return; if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); msleep(1000); } while (!time_after_eq(jiffies, wtime));}static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha){ uint16_t fw_ddb_index; int status = QLA_SUCCESS; /* free the ddb list if is not empty */ if (!list_empty(&ha->ddb_list)) qla4xxx_free_ddb_list(ha); for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) ha->fw_ddb_index_map[fw_ddb_index] = (struct ddb_entry *)INVALID_ENTRY; ha->tot_ddbs = 0; qla4xxx_flush_AENS(ha); /* * First perform device discovery for active * fw ddb indexes and build * ddb list. */ if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) return status; /* Wait for an AEN */ qla4xxx_devices_ready(ha); /* * Targets can come online after the inital discovery, so processing * the aens here will catch them. */ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) qla4xxx_process_aen(ha, PROCESS_ALL_AENS); return status;}/** * qla4xxx_update_ddb_list - update the driver ddb list * @ha: pointer to host adapter structure. * * This routine obtains device information from the F/W database after * firmware or adapter resets. The device table is preserved. **/int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha){ int status = QLA_SUCCESS; struct ddb_entry *ddb_entry, *detemp; /* Update the device information for all devices. */ list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) { qla4xxx_update_ddb_entry(ha, ddb_entry, ddb_entry->fw_ddb_index); if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked " "ONLINE\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) qla4xxx_mark_device_missing(ha, ddb_entry); } return status;}/** * qla4xxx_relogin_device - re-establish session * @ha: Pointer to host adapter structure. * @ddb_entry: Pointer to device database entry * * This routine does a session relogin with the specified device. * The ddb entry must be assigned prior to making this call. **/int qla4xxx_relogin_device(struct scsi_qla_host *ha, struct ddb_entry * ddb_entry){ uint16_t relogin_timer; relogin_timer = max(ddb_entry->default_relogin_timeout, (uint16_t)RELOGIN_TOV); atomic_set(&ddb_entry->relogin_timer, relogin_timer); DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, ddb_entry->fw_ddb_index, relogin_timer)); qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0); return QLA_SUCCESS;}static int qla4xxx_config_nvram(struct scsi_qla_host *ha){ unsigned long flags; union external_hw_config_reg extHwConfig; DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no, __func__)); if (ql4xxx_lock_flash(ha) != QLA_SUCCESS) return (QLA_ERROR); if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) { ql4xxx_unlock_flash(ha); return (QLA_ERROR); } /* Get EEPRom Parameters from NVRAM and validate */ dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n"); if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) { spin_lock_irqsave(&ha->hardware_lock, flags); extHwConfig.Asuint32_t = rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha)); spin_unlock_irqrestore(&ha->hardware_lock, flags); } else { /* * QLogic adapters should always have a valid NVRAM. * If not valid, do not load. */ dev_warn(&ha->pdev->dev, "scsi%ld: %s: EEProm checksum invalid. " "Please update your EEPROM\n", ha->host_no, __func__); /* set defaults */ if (is_qla4010(ha)) extHwConfig.Asuint32_t = 0x1912; else if (is_qla4022(ha) | is_qla4032(ha)) extHwConfig.Asuint32_t = 0x0023; } DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n", ha->host_no, __func__, extHwConfig.Asuint32_t)); spin_lock_irqsave(&ha->hardware_lock, flags); writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha)); readl(isp_ext_hw_conf(ha)); spin_unlock_irqrestore(&ha->hardware_lock, flags); ql4xxx_unlock_nvram(ha); ql4xxx_unlock_flash(ha); return (QLA_SUCCESS);}static void qla4x00_pci_config(struct scsi_qla_host *ha){ uint16_t w; int status; dev_info(&ha->pdev->dev, "Configuring PCI space...\n"); pci_set_master(ha->pdev); status = pci_set_mwi(ha->pdev); /* * We want to respect framework's setting of PCI configuration space * command register and also want to make sure that all bits of * interest to us are properly set in command register. */ pci_read_config_word(ha->pdev, PCI_COMMAND, &w); w |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; w &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(ha->pdev, PCI_COMMAND, w);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?