ql4_init.c

来自「linux 内核源代码」· C语言 代码 · 共 1,349 行 · 第 1/3 页

C
1,349
字号
/* * QLogic iSCSI HBA Driver * Copyright (c)  2003-2006 QLogic Corporation * * See LICENSE.qla4xxx for copyright and licensing details. */#include "ql4_def.h"#include "ql4_glbl.h"#include "ql4_dbg.h"#include "ql4_inline.h"static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,					    uint32_t fw_ddb_index);static void ql4xxx_set_mac_number(struct scsi_qla_host *ha){	uint32_t value;	uint8_t func_number;	unsigned long flags;	/* Get the function number */	spin_lock_irqsave(&ha->hardware_lock, flags);	value = readw(&ha->reg->ctrl_status);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	func_number = (uint8_t) ((value >> 4) & 0x30);	switch (value & ISP_CONTROL_FN_MASK) {	case ISP_CONTROL_FN0_SCSI:		ha->mac_index = 1;		break;	case ISP_CONTROL_FN1_SCSI:		ha->mac_index = 3;		break;	default:		DEBUG2(printk("scsi%ld: %s: Invalid function number, "			      "ispControlStatus = 0x%x\n", ha->host_no,			      __func__, value));		break;	}	DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__,		      ha->mac_index));}/** * qla4xxx_free_ddb - deallocate ddb * @ha: pointer to host adapter structure. * @ddb_entry: pointer to device database entry * * This routine deallocates and unlinks the specified ddb_entry from the * adapter's **/static void qla4xxx_free_ddb(struct scsi_qla_host *ha,			     struct ddb_entry *ddb_entry){	/* Remove device entry from list */	list_del_init(&ddb_entry->list);	/* Remove device pointer from index mapping arrays */	ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] =		(struct ddb_entry *) INVALID_ENTRY;	ha->tot_ddbs--;	/* Free memory and scsi-ml struct for device entry */	qla4xxx_destroy_sess(ddb_entry);}/** * qla4xxx_free_ddb_list - deallocate all ddbs * @ha: pointer to host adapter structure. * * This routine deallocates and removes all devices on the sppecified adapter. **/void qla4xxx_free_ddb_list(struct scsi_qla_host *ha){	struct list_head *ptr;	struct ddb_entry *ddb_entry;	while (!list_empty(&ha->ddb_list)) {		ptr = ha->ddb_list.next;		/* Free memory for device entry and remove */		ddb_entry = list_entry(ptr, struct ddb_entry, list);		qla4xxx_free_ddb(ha, ddb_entry);	}}/** * qla4xxx_init_rings - initialize hw queues * @ha: pointer to host adapter structure. * * This routine initializes the internal queues for the specified adapter. * The QLA4010 requires us to restart the queues at index 0. * The QLA4000 doesn't care, so just default to QLA4010's requirement. **/int qla4xxx_init_rings(struct scsi_qla_host *ha){	unsigned long flags = 0;	/* Initialize request queue. */	spin_lock_irqsave(&ha->hardware_lock, flags);	ha->request_out = 0;	ha->request_in = 0;	ha->request_ptr = &ha->request_ring[ha->request_in];	ha->req_q_count = REQUEST_QUEUE_DEPTH;	/* Initialize response queue. */	ha->response_in = 0;	ha->response_out = 0;	ha->response_ptr = &ha->response_ring[ha->response_out];	/*	 * Initialize DMA Shadow registers.  The firmware is really supposed to	 * take care of this, but on some uniprocessor systems, the shadow	 * registers aren't cleared-- causing the interrupt_handler to think	 * there are responses to be processed when there aren't.	 */	ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);	ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);	wmb();	writel(0, &ha->reg->req_q_in);	writel(0, &ha->reg->rsp_q_out);	readl(&ha->reg->rsp_q_out);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	return QLA_SUCCESS;}/** * qla4xxx_validate_mac_address - validate adapter MAC address(es) * @ha: pointer to host adapter structure. * **/static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha){	struct flash_sys_info *sys_info;	dma_addr_t sys_info_dma;	int status = QLA_ERROR;	sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),				      &sys_info_dma, GFP_KERNEL);	if (sys_info == NULL) {		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",			      ha->host_no, __func__));		goto exit_validate_mac_no_free;	}	memset(sys_info, 0, sizeof(*sys_info));	/* Get flash sys info */	if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO,			      sizeof(*sys_info)) != QLA_SUCCESS) {		DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "			      "failed\n", ha->host_no, __func__));		goto exit_validate_mac;	}	/* Save M.A.C. address & serial_number */	memcpy(ha->my_mac, &sys_info->physAddr[0].address[0],	       min(sizeof(ha->my_mac),		   sizeof(sys_info->physAddr[0].address)));	memcpy(ha->serial_number, &sys_info->acSerialNumber,	       min(sizeof(ha->serial_number),		   sizeof(sys_info->acSerialNumber)));	status = QLA_SUCCESS; exit_validate_mac:	dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,			  sys_info_dma); exit_validate_mac_no_free:	return status;}/** * qla4xxx_init_local_data - initialize adapter specific local data * @ha: pointer to host adapter structure. * **/static int qla4xxx_init_local_data(struct scsi_qla_host *ha){	/* Initilize aen queue */	ha->aen_q_count = MAX_AEN_ENTRIES;	return qla4xxx_get_firmware_status(ha);}static int qla4xxx_fw_ready(struct scsi_qla_host *ha){	uint32_t timeout_count;	int ready = 0;	DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n"));	for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0;	     timeout_count--) {		if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))			qla4xxx_get_dhcp_ip_address(ha);		/* Get firmware state. */		if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) {			DEBUG2(printk("scsi%ld: %s: unable to get firmware "				      "state\n", ha->host_no, __func__));			break;		}		if (ha->firmware_state & FW_STATE_ERROR) {			DEBUG2(printk("scsi%ld: %s: an unrecoverable error has"				      " occurred\n", ha->host_no, __func__));			break;		}		if (ha->firmware_state & FW_STATE_CONFIG_WAIT) {			/*			 * The firmware has not yet been issued an Initialize			 * Firmware command, so issue it now.			 */			if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR)				break;			/* Go back and test for ready state - no wait. */			continue;		}		if (ha->firmware_state == FW_STATE_READY) {			DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n"));			/* The firmware is ready to process SCSI commands. */			DEBUG2(dev_info(&ha->pdev->dev,					  "scsi%ld: %s: MEDIA TYPE - %s\n",					  ha->host_no,					  __func__, (ha->addl_fw_state &						     FW_ADDSTATE_OPTICAL_MEDIA)					  != 0 ? "OPTICAL" : "COPPER"));			DEBUG2(dev_info(&ha->pdev->dev,					  "scsi%ld: %s: DHCP STATE Enabled "					  "%s\n",					  ha->host_no, __func__,					  (ha->addl_fw_state &					   FW_ADDSTATE_DHCP_ENABLED) != 0 ?					  "YES" : "NO"));			DEBUG2(dev_info(&ha->pdev->dev,					  "scsi%ld: %s: LINK %s\n",					  ha->host_no, __func__,					  (ha->addl_fw_state &					   FW_ADDSTATE_LINK_UP) != 0 ?					  "UP" : "DOWN"));			DEBUG2(dev_info(&ha->pdev->dev,					  "scsi%ld: %s: iSNS Service "					  "Started %s\n",					  ha->host_no, __func__,					  (ha->addl_fw_state &					   FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ?					  "YES" : "NO"));			ready = 1;			break;		}		DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - "			      "seconds expired= %d\n", ha->host_no, __func__,			      ha->firmware_state, ha->addl_fw_state,			      timeout_count));		if (is_qla4032(ha) &&			!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) &&			(timeout_count < ADAPTER_INIT_TOV - 5)) {			break;		}		msleep(1000);	}			/* end of for */	if (timeout_count == 0)		DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",			      ha->host_no, __func__));	if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)  {		DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to"			      " grab an IP address from DHCP server\n",			      ha->host_no, __func__));		ready = 1;	}	return ready;}/** * qla4xxx_init_firmware - initializes the firmware. * @ha: pointer to host adapter structure. * **/static int qla4xxx_init_firmware(struct scsi_qla_host *ha){	int status = QLA_ERROR;	dev_info(&ha->pdev->dev, "Initializing firmware..\n");	if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) {		DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware "			      "control block\n", ha->host_no, __func__));		return status;	}	if (!qla4xxx_fw_ready(ha))		return status;	return qla4xxx_get_firmware_status(ha);}static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,						uint32_t fw_ddb_index,						uint32_t *new_tgt){	struct dev_db_entry *fw_ddb_entry = NULL;	dma_addr_t fw_ddb_entry_dma;	struct ddb_entry *ddb_entry = NULL;	int found = 0;	uint32_t device_state;	*new_tgt = 0;	/* Make sure the dma buffer is valid */	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,					  sizeof(*fw_ddb_entry),					  &fw_ddb_entry_dma, GFP_KERNEL);	if (fw_ddb_entry == NULL) {		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",			      ha->host_no, __func__));		return NULL;	}	if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,				    fw_ddb_entry_dma, NULL, NULL,				    &device_state, NULL, NULL, NULL) ==	    QLA_ERROR) {		DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "			      "fw_ddb_index %d\n", ha->host_no, __func__,			      fw_ddb_index));		return NULL;	}	/* Allocate DDB if not already allocated. */	DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,		      __func__, fw_ddb_index));	list_for_each_entry(ddb_entry, &ha->ddb_list, list) {		if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name,			   ISCSI_NAME_SIZE) == 0) {			found++;			break;		}	}	if (!found) {		DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "			      "new ddb\n", ha->host_no, __func__,			      fw_ddb_index));		*new_tgt = 1;		ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);	}	/* if not found allocate new ddb */	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,			  fw_ddb_entry_dma);	return ddb_entry;}/** * qla4xxx_update_ddb_entry - update driver's internal ddb * @ha: pointer to host adapter structure. * @ddb_entry: pointer to device database structure to be filled * @fw_ddb_index: index of the ddb entry in fw ddb table * * This routine updates the driver's internal device database entry * with information retrieved from the firmware's device database * entry for the specified device. The ddb_entry->fw_ddb_index field * must be initialized prior to	calling this routine * **/static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,				    struct ddb_entry *ddb_entry,				    uint32_t fw_ddb_index){	struct dev_db_entry *fw_ddb_entry = NULL;	dma_addr_t fw_ddb_entry_dma;	int status = QLA_ERROR;	if (ddb_entry == NULL) {		DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,			      __func__));		goto exit_update_ddb;	}	/* Make sure the dma buffer is valid */	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,					  sizeof(*fw_ddb_entry),					  &fw_ddb_entry_dma, GFP_KERNEL);	if (fw_ddb_entry == NULL) {		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",			      ha->host_no, __func__));		goto exit_update_ddb;	}	if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,				    fw_ddb_entry_dma, NULL, NULL,				    &ddb_entry->fw_ddb_device_state, NULL,				    &ddb_entry->tcp_source_port_num,				    &ddb_entry->connection_id) ==	    QLA_ERROR) {		DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "			      "fw_ddb_index %d\n", ha->host_no, __func__,			      fw_ddb_index));		goto exit_update_ddb;	}	status = QLA_SUCCESS;	ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);	ddb_entry->task_mgmt_timeout =		le16_to_cpu(fw_ddb_entry->def_timeout);	ddb_entry->CmdSn = 0;	ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle);	ddb_entry->default_relogin_timeout =		le16_to_cpu(fw_ddb_entry->def_timeout);	ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);	/* Update index in case it changed */	ddb_entry->fw_ddb_index = fw_ddb_index;	ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;	ddb_entry->port = le16_to_cpu(fw_ddb_entry->port);	ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);	memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],	       min(sizeof(ddb_entry->iscsi_name),		   sizeof(fw_ddb_entry->iscsi_name)));	memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],	       min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));	DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",		      ha->host_no, __func__, fw_ddb_index,		      ddb_entry->fw_ddb_device_state, status)); exit_update_ddb:	if (fw_ddb_entry)		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),				  fw_ddb_entry, fw_ddb_entry_dma);	return status;}/**

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?