ql4_init.c
来自「linux 内核源代码」· C语言 代码 · 共 1,349 行 · 第 1/3 页
C
1,349 行
}static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha){ int status = QLA_ERROR; uint32_t max_wait_time; unsigned long flags; uint32_t mbox_status; dev_info(&ha->pdev->dev, "Starting firmware ...\n"); /* * Start firmware from flash ROM * * WORKAROUND: Stuff a non-constant value that the firmware can * use as a seed for a random number generator in MB7 prior to * setting BOOT_ENABLE. Fixes problem where the TCP * connections use the same TCP ports after each reboot, * causing some connections to not get re-established. */ DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n", ha->host_no, __func__)); spin_lock_irqsave(&ha->hardware_lock, flags); writel(jiffies, &ha->reg->mailbox[7]); if (is_qla4022(ha) | is_qla4032(ha)) writel(set_rmask(NVR_WRITE_ENABLE), &ha->reg->u1.isp4022.nvram); writel(2, &ha->reg->mailbox[6]); readl(&ha->reg->mailbox[6]); writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for firmware to come UP. */ max_wait_time = FIRMWARE_UP_TOV * 4; do { uint32_t ctrl_status; spin_lock_irqsave(&ha->hardware_lock, flags); ctrl_status = readw(&ha->reg->ctrl_status); mbox_status = readw(&ha->reg->mailbox[0]); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR)) break; if (mbox_status == MBOX_STS_COMMAND_COMPLETE) break; DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to " "complete... ctrl_sts=0x%x, remaining=%d\n", ha->host_no, __func__, ctrl_status, max_wait_time)); msleep(250); } while ((max_wait_time--)); if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { DEBUG(printk("scsi%ld: %s: Firmware has started\n", ha->host_no, __func__)); spin_lock_irqsave(&ha->hardware_lock, flags); writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); status = QLA_SUCCESS; } else { printk(KERN_INFO "scsi%ld: %s: Boot firmware failed " "- mbox status 0x%x\n", ha->host_no, __func__, mbox_status); status = QLA_ERROR; } return status;}int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a){#define QL4_LOCK_DRVR_WAIT 60#define QL4_LOCK_DRVR_SLEEP 1 int drvr_wait = QL4_LOCK_DRVR_WAIT; while (drvr_wait) { if (ql4xxx_lock_drvr(a) == 0) { ssleep(QL4_LOCK_DRVR_SLEEP); if (drvr_wait) { DEBUG2(printk("scsi%ld: %s: Waiting for " "Global Init Semaphore(%d)...\n", a->host_no, __func__, drvr_wait)); } drvr_wait -= QL4_LOCK_DRVR_SLEEP; } else { DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " "acquired\n", a->host_no, __func__)); return QLA_SUCCESS; } } return QLA_ERROR;}/** * qla4xxx_start_firmware - starts qla4xxx firmware * @ha: Pointer to host adapter structure. * * This routine performs the necessary steps to start the firmware for * the QLA4010 adapter. **/static int qla4xxx_start_firmware(struct scsi_qla_host *ha){ unsigned long flags = 0; uint32_t mbox_status; int status = QLA_ERROR; int soft_reset = 1; int config_chip = 0; if (is_qla4022(ha) | is_qla4032(ha)) ql4xxx_set_mac_number(ha); if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) return QLA_ERROR; spin_lock_irqsave(&ha->hardware_lock, flags); DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no, __func__, readw(isp_port_ctrl(ha)))); DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no, __func__, readw(isp_port_status(ha)))); /* Is Hardware already initialized? */ if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) { DEBUG(printk("scsi%ld: %s: Hardware has already been " "initialized\n", ha->host_no, __func__)); /* Receive firmware boot acknowledgement */ mbox_status = readw(&ha->reg->mailbox[0]); DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= " "0x%x\n", ha->host_no, __func__, mbox_status)); /* Is firmware already booted? */ if (mbox_status == 0) { /* F/W not running, must be config by net driver */ config_chip = 1; soft_reset = 0; } else { writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { DEBUG2(printk("scsi%ld: %s: Get firmware " "state -- state = 0x%x\n", ha->host_no, __func__, ha->firmware_state)); /* F/W is running */ if (ha->firmware_state & FW_STATE_CONFIG_WAIT) { DEBUG2(printk("scsi%ld: %s: Firmware " "in known state -- " "config and " "boot, state = 0x%x\n", ha->host_no, __func__, ha->firmware_state)); config_chip = 1; soft_reset = 0; } } else { DEBUG2(printk("scsi%ld: %s: Firmware in " "unknown state -- resetting," " state = " "0x%x\n", ha->host_no, __func__, ha->firmware_state)); } spin_lock_irqsave(&ha->hardware_lock, flags); } } else { DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been " "started - resetting\n", ha->host_no, __func__)); } spin_unlock_irqrestore(&ha->hardware_lock, flags); DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ", ha->host_no, __func__, soft_reset, config_chip)); if (soft_reset) { DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no, __func__)); status = qla4xxx_soft_reset(ha); if (status == QLA_ERROR) { DEBUG(printk("scsi%d: %s: Soft Reset failed!\n", ha->host_no, __func__)); ql4xxx_unlock_drvr(ha); return QLA_ERROR; } config_chip = 1; /* Reset clears the semaphore, so aquire again */ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) return QLA_ERROR; } if (config_chip) { if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS) status = qla4xxx_start_firmware_from_flash(ha); } ql4xxx_unlock_drvr(ha); if (status == QLA_SUCCESS) { qla4xxx_get_fw_version(ha); if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags)) qla4xxx_get_crash_record(ha); } else { DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n", ha->host_no, __func__)); } return status;}/** * qla4xxx_initialize_adapter - initiailizes hba * @ha: Pointer to host adapter structure. * @renew_ddb_list: Indicates what to do with the adapter's ddb list * after adapter recovery has completed. * 0=preserve ddb list, 1=destroy and rebuild ddb list * * This routine parforms all of the steps necessary to initialize the adapter. * **/int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, uint8_t renew_ddb_list){ int status = QLA_ERROR; int8_t ip_address[IP_ADDR_LEN] = {0} ; ha->eeprom_cmd_data = 0; qla4x00_pci_config(ha); qla4xxx_disable_intrs(ha); /* Initialize the Host adapter request/response queues and firmware */ if (qla4xxx_start_firmware(ha) == QLA_ERROR) goto exit_init_hba; if (qla4xxx_validate_mac_address(ha) == QLA_ERROR) goto exit_init_hba; if (qla4xxx_init_local_data(ha) == QLA_ERROR) goto exit_init_hba; status = qla4xxx_init_firmware(ha); if (status == QLA_ERROR) goto exit_init_hba; /* * FW is waiting to get an IP address from DHCP server: Skip building * the ddb_list and wait for DHCP lease acquired aen to come in * followed by 0x8014 aen" to trigger the tgt discovery process. */ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) goto exit_init_online; /* Skip device discovery if ip and subnet is zero */ if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 || memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0) goto exit_init_online; if (renew_ddb_list == PRESERVE_DDB_LIST) { /* * We want to preserve lun states (i.e. suspended, etc.) * for recovery initiated by the driver. So just update * the device states for the existing ddb_list. */ qla4xxx_reinitialize_ddb_list(ha); } else if (renew_ddb_list == REBUILD_DDB_LIST) { /* * We want to build the ddb_list from scratch during * driver initialization and recovery initiated by the * INT_HBA_RESET IOCTL. */ status = qla4xxx_initialize_ddb_list(ha); if (status == QLA_ERROR) { DEBUG2(printk("%s(%ld) Error occurred during build" "ddb list\n", __func__, ha->host_no)); goto exit_init_hba; } } if (!ha->tot_ddbs) { DEBUG2(printk("scsi%ld: Failed to initialize devices or none " "present in Firmware device database\n", ha->host_no)); }exit_init_online: set_bit(AF_ONLINE, &ha->flags);exit_init_hba: return status;}/** * qla4xxx_add_device_dynamically - ddb addition due to an AEN * @ha: Pointer to host adapter structure. * @fw_ddb_index: Firmware's device database index * * This routine processes adds a device as a result of an 8014h AEN. **/static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, uint32_t fw_ddb_index){ struct ddb_entry * ddb_entry; uint32_t new_tgt; /* First allocate a device structure */ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt); if (ddb_entry == NULL) { DEBUG2(printk(KERN_WARNING "scsi%ld: Unable to allocate memory to add " "fw_ddb_index %d\n", ha->host_no, fw_ddb_index)); return; } if (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) { /* Target has been bound to a new fw_ddb_index */ qla4xxx_free_ddb(ha, ddb_entry); ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); if (ddb_entry == NULL) { DEBUG2(printk(KERN_WARNING "scsi%ld: Unable to allocate memory" " to add fw_ddb_index %d\n", ha->host_no, fw_ddb_index)); return; } } 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(KERN_WARNING "scsi%ld: failed to add new device at index " "[%d]\n Unable to retrieve fw ddb entry\n", ha->host_no, fw_ddb_index)); qla4xxx_free_ddb(ha, ddb_entry); return; } if (qla4xxx_add_sess(ddb_entry)) { DEBUG2(printk(KERN_WARNING "scsi%ld: failed to add new device at index " "[%d]\n Unable to add connection and session\n", ha->host_no, fw_ddb_index)); qla4xxx_free_ddb(ha, ddb_entry); }}/** * qla4xxx_process_ddb_changed - process ddb state change * @ha - Pointer to host adapter structure. * @fw_ddb_index - Firmware's device database index * @state - Device state * * This routine processes a Decive Database Changed AEN Event. **/int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, uint32_t state){ struct ddb_entry * ddb_entry; uint32_t old_fw_ddb_device_state; /* check for out of range index */ if (fw_ddb_index >= MAX_DDB_ENTRIES) return QLA_ERROR; /* Get the corresponging ddb entry */ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); /* Device does not currently exist in our database. */ if (ddb_entry == NULL) { if (state == DDB_DS_SESSION_ACTIVE) qla4xxx_add_device_dynamically(ha, fw_ddb_index); return QLA_SUCCESS; } /* Device already exists in our database. */ old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for " "index [%d]\n", ha->host_no, __func__, ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); if (old_fw_ddb_device_state == state && state == DDB_DS_SESSION_ACTIVE) { /* Do nothing, state not changed. */ return QLA_SUCCESS; } ddb_entry->fw_ddb_device_state = state; /* Device is back online. */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count); atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); iscsi_if_create_session_done(ddb_entry->conn); /* * Change the lun state to READY in case the lun TIMEOUT before * the device came back. */ } else { /* Device went away, try to relogin. */ /* Mark device missing */ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) qla4xxx_mark_device_missing(ha, ddb_entry); /* * Relogin if device state changed to a not active state. * However, do not relogin if this aen is a result of an IOCTL * logout (DF_NO_RELOGIN) or if this is a discovered device. */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && !test_bit(DF_RELOGIN, &ddb_entry->flags) && !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) { /* * This triggers a relogin. After the relogin_timer * expires, the relogin gets scheduled. We must wait a * minimum amount of time since receiving an 0x8014 AEN * with failed device_state or a logout response before * we can issue another relogin. */ /* Firmware padds this timeout: (time2wait +1). * Driver retry to login should be longer than F/W. * Otherwise F/W will fail * set_ddb() mbx cmd with 0x4005 since it still * counting down its time2wait. */ atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->retry_relogin_timer, ddb_entry->default_time2wait + 4); } } return QLA_SUCCESS;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?