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