Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a49a78e authored by Vikas Chaudhary's avatar Vikas Chaudhary Committed by James Bottomley
Browse files

[SCSI] qla4xxx: added IPv6 support.

parent 3487d9e7
Loading
Loading
Loading
Loading
+38 −2
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@
 */
#define MAC_ADDR_LEN			6	/* in bytes */
#define IP_ADDR_LEN			4	/* in bytes */
#define IPv6_ADDR_LEN			16	/* IPv6 address size */
#define DRIVER_NAME			"qla4xxx"

#define MAX_LINKED_CMDS_PER_LUN		3
@@ -220,7 +221,7 @@ struct ddb_entry {

	uint16_t os_target_id;	/* Target ID */
	uint16_t fw_ddb_index;	/* DDB firmware index */
	uint8_t reserved[2];
	uint16_t options;
	uint32_t fw_ddb_device_state; /* F/W Device State  -- see ql4_fw.h */

	uint32_t CmdSn;
@@ -245,10 +246,18 @@ struct ddb_entry {

	uint16_t port;
	uint32_t tpgt;
	uint8_t ip_addr[ISCSI_IPADDR_SIZE];
	uint8_t ip_addr[IP_ADDR_LEN];
	uint8_t iscsi_name[ISCSI_NAME_SIZE];	/* 72 x48 */
	uint8_t iscsi_alias[0x20];
	uint8_t isid[6];
	uint16_t iscsi_max_burst_len;
	uint16_t iscsi_max_outsnd_r2t;
	uint16_t iscsi_first_burst_len;
	uint16_t iscsi_max_rcv_data_seg_len;
	uint16_t iscsi_max_snd_data_seg_len;

	struct in6_addr remote_ipv6_addr;
	struct in6_addr link_local_ipv6_addr;
};

/*
@@ -441,8 +450,35 @@ struct scsi_qla_host {

	/* Saved srb for status continuation entry processing */
	struct srb *status_srb;

	/* IPv6 support info from InitFW */
	uint8_t acb_version;
	uint8_t ipv4_addr_state;
	uint16_t ipv4_options;

	uint32_t resvd2;
	uint32_t ipv6_options;
	uint32_t ipv6_addl_options;
	uint8_t ipv6_link_local_state;
	uint8_t ipv6_addr0_state;
	uint8_t ipv6_addr1_state;
	uint8_t ipv6_default_router_state;
	struct in6_addr ipv6_link_local_addr;
	struct in6_addr ipv6_addr0;
	struct in6_addr ipv6_addr1;
	struct in6_addr ipv6_default_router_addr;
};

static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
{
	return ((ha->ipv4_options & IPOPT_IPv4_PROTOCOL_ENABLE) != 0);
}

static inline int is_ipv6_enabled(struct scsi_qla_host *ha)
{
	return ((ha->ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) != 0);
}

static inline int is_qla4010(struct scsi_qla_host *ha)
{
	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010;
+38 −7
Original line number Diff line number Diff line
@@ -258,13 +258,15 @@ union external_hw_config_reg {
/* Mailbox 1 */
#define FW_STATE_READY				0x0000
#define FW_STATE_CONFIG_WAIT			0x0001
#define FW_STATE_WAIT_LOGIN			0x0002
#define FW_STATE_WAIT_AUTOCONNECT		0x0002
#define FW_STATE_ERROR				0x0004
#define FW_STATE_DHCP_IN_PROGRESS		0x0008
#define FW_STATE_CONFIGURING_IP			0x0008

/* Mailbox 3 */
#define FW_ADDSTATE_OPTICAL_MEDIA		0x0001
#define FW_ADDSTATE_DHCP_ENABLED		0x0002
#define FW_ADDSTATE_DHCPv4_ENABLED		0x0002
#define FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED	0x0004
#define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED	0x0008
#define FW_ADDSTATE_LINK_UP			0x0010
#define FW_ADDSTATE_ISNS_SVC_ENABLED		0x0020
#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS	0x006B
@@ -320,6 +322,8 @@ union external_hw_config_reg {
/* Host Adapter Initialization Control Block (from host) */
struct addr_ctrl_blk {
	uint8_t version;	/* 00 */
#define  IFCB_VER_MIN			0x01
#define  IFCB_VER_MAX			0x02
	uint8_t control;	/* 01 */

	uint16_t fw_options;	/* 02-03 */
@@ -351,11 +355,16 @@ struct addr_ctrl_blk {
	uint16_t iscsi_opts;	/* 30-31 */
	uint16_t ipv4_tcp_opts;	/* 32-33 */
	uint16_t ipv4_ip_opts;	/* 34-35 */
#define  IPOPT_IPv4_PROTOCOL_ENABLE	0x8000

	uint16_t iscsi_max_pdu_size;	/* 36-37 */
	uint8_t ipv4_tos;	/* 38 */
	uint8_t ipv4_ttl;	/* 39 */
	uint8_t acb_version;	/* 3A */
#define ACB_NOT_SUPPORTED		0x00
#define ACB_SUPPORTED			0x02 /* Capable of ACB Version 2
						Features */

	uint8_t res2;	/* 3B */
	uint16_t def_timeout;	/* 3C-3D */
	uint16_t iscsi_fburst_len;	/* 3E-3F */
@@ -397,16 +406,35 @@ struct addr_ctrl_blk {
	uint32_t cookie;	/* 200-203 */
	uint16_t ipv6_port;	/* 204-205 */
	uint16_t ipv6_opts;	/* 206-207 */
#define IPV6_OPT_IPV6_PROTOCOL_ENABLE	0x8000

	uint16_t ipv6_addtl_opts;	/* 208-209 */
#define IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE	0x0002 /* Pri ACB
								  Only */
#define IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR		0x0001

	uint16_t ipv6_tcp_opts;	/* 20A-20B */
	uint8_t ipv6_tcp_wsf;	/* 20C */
	uint16_t ipv6_flow_lbl;	/* 20D-20F */
	uint8_t ipv6_gw_addr[16];	/* 210-21F */
	uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */
	uint16_t ipv6_vlan_tag;	/* 220-221 */
	uint8_t ipv6_lnk_lcl_addr_state;/* 222 */
	uint8_t ipv6_addr0_state;	/* 223 */
	uint8_t ipv6_addr1_state;	/* 224 */
	uint8_t ipv6_gw_state;	/* 225 */
#define IP_ADDRSTATE_UNCONFIGURED	0
#define IP_ADDRSTATE_INVALID		1
#define IP_ADDRSTATE_ACQUIRING		2
#define IP_ADDRSTATE_TENTATIVE		3
#define IP_ADDRSTATE_DEPRICATED		4
#define IP_ADDRSTATE_PREFERRED		5
#define IP_ADDRSTATE_DISABLING		6

	uint8_t ipv6_dflt_rtr_state;    /* 225 */
#define IPV6_RTRSTATE_UNKNOWN                   0
#define IPV6_RTRSTATE_MANUAL                    1
#define IPV6_RTRSTATE_ADVERTISED                3
#define IPV6_RTRSTATE_STALE                     4

	uint8_t ipv6_traffic_class;	/* 226 */
	uint8_t ipv6_hop_limit;	/* 227 */
	uint8_t ipv6_if_id[8];	/* 228-22F */
@@ -424,7 +452,7 @@ struct addr_ctrl_blk {

struct init_fw_ctrl_blk {
	struct addr_ctrl_blk pri;
	struct addr_ctrl_blk sec;
/*	struct addr_ctrl_blk sec;*/
};

/*************************************************************************/
@@ -433,6 +461,9 @@ struct dev_db_entry {
	uint16_t options;	/* 00-01 */
#define DDB_OPT_DISC_SESSION  0x10
#define DDB_OPT_TARGET	      0x02 /* device is a target */
#define DDB_OPT_IPV6_DEVICE	0x100
#define DDB_OPT_IPV6_NULL_LINK_LOCAL		0x800 /* post connection */
#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL	0x800 /* pre connection */

	uint16_t exec_throttle;	/* 02-03 */
	uint16_t exec_count;	/* 04-05 */
@@ -468,7 +499,7 @@ struct dev_db_entry {
					 * pointer to a string so we
					 * don't have to reserve soooo
					 * much RAM */
	uint8_t ipv6_addr[0x10];/* 1A0-1AF */
	uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */
	uint8_t res5[0x10];	/* 1B0-1BF */
	uint16_t ddb_link;	/* 1C0-1C1 */
	uint16_t chap_tbl_idx;	/* 1C2-1C3 */
+178 −40
Original line number Diff line number Diff line
@@ -189,6 +189,78 @@ static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
	return qla4xxx_get_firmware_status(ha);
}

static uint8_t
qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha)
{
	uint8_t ipv4_wait = 0;
	uint8_t ipv6_wait = 0;
	int8_t ip_address[IPv6_ADDR_LEN] = {0} ;

	/* If both IPv4 & IPv6 are enabled, possibly only one
	 * IP address may be acquired, so check to see if we
	 * need to wait for another */
	if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) {
		if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) &&
		    ((ha->addl_fw_state &
				    FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) {
			ipv4_wait = 1;
		}
		if (((ha->ipv6_addl_options &
			    IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) &&
		    ((ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) ||
		     (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) ||
		     (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING))) {

			ipv6_wait = 1;

			if ((ha->ipv6_link_local_state ==
						     IP_ADDRSTATE_PREFERRED) ||
			    (ha->ipv6_addr0_state == IP_ADDRSTATE_PREFERRED) ||
			    (ha->ipv6_addr1_state == IP_ADDRSTATE_PREFERRED)) {
				DEBUG2(printk(KERN_INFO "scsi%ld: %s: "
					      "Preferred IP configured."
					      " Don't wait!\n", ha->host_no,
					      __func__));
				ipv6_wait = 0;
			}
			if (memcmp(&ha->ipv6_default_router_addr, ip_address,
				IPv6_ADDR_LEN) == 0) {
				DEBUG2(printk(KERN_INFO "scsi%ld: %s: "
					      "No Router configured. "
					      "Don't wait!\n", ha->host_no,
					      __func__));
				ipv6_wait = 0;
			}
			if ((ha->ipv6_default_router_state ==
						IPV6_RTRSTATE_MANUAL) &&
			    (ha->ipv6_link_local_state ==
						IP_ADDRSTATE_TENTATIVE) &&
			    (memcmp(&ha->ipv6_link_local_addr,
				    &ha->ipv6_default_router_addr, 4) == 0)) {
				DEBUG2(printk("scsi%ld: %s: LinkLocal Router & "
					"IP configured. Don't wait!\n",
					ha->host_no, __func__));
				ipv6_wait = 0;
			}
		}
		if (ipv4_wait || ipv6_wait) {
			DEBUG2(printk("scsi%ld: %s: Wait for additional "
				      "IP(s) \"", ha->host_no, __func__));
			if (ipv4_wait)
				DEBUG2(printk("IPv4 "));
			if (ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING)
				DEBUG2(printk("IPv6LinkLocal "));
			if (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING)
				DEBUG2(printk("IPv6Addr0 "));
			if (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING)
				DEBUG2(printk("IPv6Addr1 "));
			DEBUG2(printk("\"\n"));
		}
	}

	return ipv4_wait|ipv6_wait;
}

static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
{
	uint32_t timeout_count;
@@ -226,21 +298,62 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
			continue;
		}

		if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) {
			DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:"
				      "AUTOCONNECT in progress\n",
				      ha->host_no, __func__));
		}

		if (ha->firmware_state & FW_STATE_CONFIGURING_IP) {
			DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:"
				      " CONFIGURING IP\n",
				      ha->host_no, __func__));
			/*
			 * Check for link state after 15 secs and if link is
			 * still DOWN then, cable is unplugged. Ignore "DHCP
			 * in Progress/CONFIGURING IP" bit to check if firmware
			 * is in ready state or not after 15 secs.
			 * This is applicable for both 2.x & 3.x firmware
			 */
			if (timeout_count <= (ADAPTER_INIT_TOV - 15)) {
				if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) {
					DEBUG2(printk(KERN_INFO "scsi%ld: %s:"
						  " LINK UP (Cable plugged)\n",
						  ha->host_no, __func__));
				} else if (ha->firmware_state &
					  (FW_STATE_CONFIGURING_IP |
							     FW_STATE_READY)) {
					DEBUG2(printk(KERN_INFO "scsi%ld: %s: "
						"LINK DOWN (Cable unplugged)\n",
						ha->host_no, __func__));
					ha->firmware_state = FW_STATE_READY;
				}
			}
		}

		if (ha->firmware_state == FW_STATE_READY) {
			DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n"));
			/* The firmware is ready to process SCSI commands. */
			/* If DHCP IP Addr is available, retrieve it now. */
			if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR,
								&ha->dpc_flags))
				qla4xxx_get_dhcp_ip_address(ha);

			if (!qla4xxx_wait_for_ip_config(ha) ||
							timeout_count == 1) {
				DEBUG2(dev_info(&ha->pdev->dev,
					  "scsi%ld: %s: MEDIA TYPE - %s\n",
					  ha->host_no,
						"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 ?
					"scsi%ld: %s: DHCPv4 STATE"
					" Enabled %s\n", ha->host_no,
					 __func__, (ha->addl_fw_state &
					 FW_ADDSTATE_DHCPv4_ENABLED) != 0 ?
					"YES" : "NO"));
				DEBUG2(dev_info(&ha->pdev->dev,
					"scsi%ld: %s: LINK %s\n",
@@ -259,6 +372,7 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
				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,
@@ -272,15 +386,19 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
		msleep(1000);
	}			/* end of for */

	if (timeout_count == 0)
	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",
	if (ha->firmware_state & FW_STATE_CONFIGURING_IP) {
		DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting "
			      "it's waiting to configure an IP address\n",
			       ha->host_no, __func__));
		ready = 1;
	} else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) {
		DEBUG2(printk("scsi%ld: %s: FW initialized, but "
			      "auto-discovery still in process\n",
			       ha->host_no, __func__));
	}

	return ready;
@@ -419,6 +537,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
	}

	status = QLA_SUCCESS;
	ddb_entry->options = le16_to_cpu(fw_ddb_entry->options);
	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);
@@ -442,6 +561,25 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
	memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
	       min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));

	ddb_entry->iscsi_max_burst_len = fw_ddb_entry->iscsi_max_burst_len;
	ddb_entry->iscsi_max_outsnd_r2t = fw_ddb_entry->iscsi_max_outsnd_r2t;
	ddb_entry->iscsi_first_burst_len = fw_ddb_entry->iscsi_first_burst_len;
	ddb_entry->iscsi_max_rcv_data_seg_len =
				fw_ddb_entry->iscsi_max_rcv_data_seg_len;
	ddb_entry->iscsi_max_snd_data_seg_len =
				fw_ddb_entry->iscsi_max_snd_data_seg_len;

	if (ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
		memcpy(&ddb_entry->remote_ipv6_addr,
			fw_ddb_entry->ip_addr,
			min(sizeof(ddb_entry->remote_ipv6_addr),
			sizeof(fw_ddb_entry->ip_addr)));
		memcpy(&ddb_entry->link_local_ipv6_addr,
			fw_ddb_entry->link_local_ipv6_addr,
			min(sizeof(ddb_entry->link_local_ipv6_addr),
			sizeof(fw_ddb_entry->link_local_ipv6_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));
@@ -1166,7 +1304,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
	 * 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)
	if (ha->firmware_state & FW_STATE_CONFIGURING_IP)
		goto exit_init_online;

	/* Skip device discovery if ip and subnet is zero */
+191 −93

File changed.

Preview size limit exceeded, changes collapsed.