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 + -
显示快捷键?