|
@@ -166,6 +166,26 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
|
|
static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
|
|
static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
|
|
int reason);
|
|
int reason);
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * iSCSI Flash DDB sysfs entry points
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn,
|
|
|
|
+ void *data, int len);
|
|
|
|
+static int
|
|
|
|
+qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ int param, char *buf);
|
|
|
|
+static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
|
|
|
|
+ int len);
|
|
|
|
+static int
|
|
|
|
+qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
|
|
|
|
+static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn);
|
|
|
|
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn);
|
|
|
|
+static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
|
|
|
|
+
|
|
static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
|
|
static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
|
|
QLA82XX_LEGACY_INTR_CONFIG;
|
|
QLA82XX_LEGACY_INTR_CONFIG;
|
|
|
|
|
|
@@ -232,6 +252,13 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
|
|
.send_ping = qla4xxx_send_ping,
|
|
.send_ping = qla4xxx_send_ping,
|
|
.get_chap = qla4xxx_get_chap_list,
|
|
.get_chap = qla4xxx_get_chap_list,
|
|
.delete_chap = qla4xxx_delete_chap,
|
|
.delete_chap = qla4xxx_delete_chap,
|
|
|
|
+ .get_flashnode_param = qla4xxx_sysfs_ddb_get_param,
|
|
|
|
+ .set_flashnode_param = qla4xxx_sysfs_ddb_set_param,
|
|
|
|
+ .new_flashnode = qla4xxx_sysfs_ddb_add,
|
|
|
|
+ .del_flashnode = qla4xxx_sysfs_ddb_delete,
|
|
|
|
+ .login_flashnode = qla4xxx_sysfs_ddb_login,
|
|
|
|
+ .logout_flashnode = qla4xxx_sysfs_ddb_logout,
|
|
|
|
+ .logout_flashnode_sid = qla4xxx_sysfs_ddb_logout_sid,
|
|
};
|
|
};
|
|
|
|
|
|
static struct scsi_transport_template *qla4xxx_scsi_transport;
|
|
static struct scsi_transport_template *qla4xxx_scsi_transport;
|
|
@@ -376,6 +403,68 @@ static umode_t qla4_attr_is_visible(int param_type, int param)
|
|
default:
|
|
default:
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+ case ISCSI_FLASHNODE_PARAM:
|
|
|
|
+ switch (param) {
|
|
|
|
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
|
|
|
|
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
|
|
|
|
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
|
|
|
|
+ case ISCSI_FLASHNODE_ENTRY_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
|
|
|
|
+ case ISCSI_FLASHNODE_PDU_INORDER:
|
|
|
|
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
|
|
|
|
+ case ISCSI_FLASHNODE_ERL:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
|
|
|
|
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
|
|
|
|
+ case ISCSI_FLASHNODE_FIRST_BURST:
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_R2T:
|
|
|
|
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
|
|
|
|
+ case ISCSI_FLASHNODE_ISID:
|
|
|
|
+ case ISCSI_FLASHNODE_TSID:
|
|
|
|
+ case ISCSI_FLASHNODE_PORT:
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_BURST:
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
|
|
|
|
+ case ISCSI_FLASHNODE_IPADDR:
|
|
|
|
+ case ISCSI_FLASHNODE_ALIAS:
|
|
|
|
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
|
|
|
|
+ case ISCSI_FLASHNODE_LOCAL_PORT:
|
|
|
|
+ case ISCSI_FLASHNODE_IPV4_TOS:
|
|
|
|
+ case ISCSI_FLASHNODE_IPV6_TC:
|
|
|
|
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
|
|
|
|
+ case ISCSI_FLASHNODE_NAME:
|
|
|
|
+ case ISCSI_FLASHNODE_TPGT:
|
|
|
|
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
|
|
|
|
+ case ISCSI_FLASHNODE_CHAP_OUT_IDX:
|
|
|
|
+ case ISCSI_FLASHNODE_USERNAME:
|
|
|
|
+ case ISCSI_FLASHNODE_PASSWORD:
|
|
|
|
+ case ISCSI_FLASHNODE_STATSN:
|
|
|
|
+ case ISCSI_FLASHNODE_EXP_STATSN:
|
|
|
|
+ case ISCSI_FLASHNODE_IS_BOOT_TGT:
|
|
|
|
+ return S_IRUGO;
|
|
|
|
+ default:
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1922,6 +2011,250 @@ static int qla4xxx_task_xmit(struct iscsi_task *task)
|
|
return -ENOSYS;
|
|
return -ENOSYS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *conn,
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry)
|
|
|
|
+{
|
|
|
|
+ unsigned long options = 0;
|
|
|
|
+ int rc = 0;
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->options);
|
|
|
|
+ conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
|
|
|
|
+ if (test_bit(OPT_IPV6_DEVICE, &options)) {
|
|
|
|
+ rc = iscsi_switch_str_param(&sess->portal_type, DEV_TYPE_IPV6);
|
|
|
|
+ if (rc)
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ } else {
|
|
|
|
+ rc = iscsi_switch_str_param(&sess->portal_type, DEV_TYPE_IPV4);
|
|
|
|
+ if (rc)
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
|
|
|
|
+ &options);
|
|
|
|
+ sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
|
|
|
|
+ sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
|
|
|
|
+ conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
|
|
|
|
+ conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
|
|
|
|
+ sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
|
|
|
|
+ sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
|
|
|
|
+ sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
|
|
|
|
+ &options);
|
|
|
|
+ sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
|
|
|
|
+ sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
|
|
|
|
+ conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
|
|
|
|
+ sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
|
|
|
|
+ &options);
|
|
|
|
+ sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
|
|
|
|
+ sess->discovery_auth_optional =
|
|
|
|
+ test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
|
|
|
|
+ if (test_bit(ISCSIOPT_ERL1, &options))
|
|
|
|
+ sess->erl |= BIT_1;
|
|
|
|
+ if (test_bit(ISCSIOPT_ERL0, &options))
|
|
|
|
+ sess->erl |= BIT_0;
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
|
|
|
|
+ conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
|
|
|
|
+ conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
|
|
|
|
+ conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
|
|
|
|
+ if (test_bit(TCPOPT_TIMER_SCALE3, &options))
|
|
|
|
+ conn->tcp_timer_scale |= BIT_3;
|
|
|
|
+ if (test_bit(TCPOPT_TIMER_SCALE2, &options))
|
|
|
|
+ conn->tcp_timer_scale |= BIT_2;
|
|
|
|
+ if (test_bit(TCPOPT_TIMER_SCALE1, &options))
|
|
|
|
+ conn->tcp_timer_scale |= BIT_1;
|
|
|
|
+
|
|
|
|
+ conn->tcp_timer_scale >>= 1;
|
|
|
|
+ conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
|
|
|
|
+ conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
|
|
|
|
+
|
|
|
|
+ conn->max_recv_dlength = BYTE_UNITS *
|
|
|
|
+ le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
|
|
|
|
+ conn->max_xmit_dlength = BYTE_UNITS *
|
|
|
|
+ le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
|
|
|
|
+ sess->first_burst = BYTE_UNITS *
|
|
|
|
+ le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
|
|
|
|
+ sess->max_burst = BYTE_UNITS *
|
|
|
|
+ le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
|
|
|
|
+ sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
|
|
|
|
+ sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
|
|
|
|
+ sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
|
|
|
|
+ sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
|
|
|
|
+ conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
|
|
|
|
+ conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
|
|
|
|
+ conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
|
|
|
|
+ conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
|
|
|
|
+ conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
|
|
|
|
+ conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
|
|
|
|
+ conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
|
|
|
|
+ conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
|
|
|
|
+ sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
|
|
|
|
+ sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
|
|
|
|
+ sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
|
|
|
|
+ sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
|
|
|
|
+
|
|
|
|
+ sess->default_taskmgmt_timeout =
|
|
|
|
+ le16_to_cpu(fw_ddb_entry->def_timeout);
|
|
|
|
+ conn->port = le16_to_cpu(fw_ddb_entry->port);
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->options);
|
|
|
|
+ conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
|
|
|
|
+ if (!conn->ipaddress) {
|
|
|
|
+ rc = -ENOMEM;
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
|
|
|
|
+ if (!conn->redirect_ipaddr) {
|
|
|
|
+ rc = -ENOMEM;
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
|
|
|
|
+ memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
|
|
|
|
+
|
|
|
|
+ if (test_bit(OPT_IPV6_DEVICE, &options)) {
|
|
|
|
+ conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
|
|
|
|
+
|
|
|
|
+ conn->link_local_ipv6_addr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
|
|
|
|
+ if (!conn->link_local_ipv6_addr) {
|
|
|
|
+ rc = -ENOMEM;
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(conn->link_local_ipv6_addr,
|
|
|
|
+ fw_ddb_entry->link_local_ipv6_addr, IPv6_ADDR_LEN);
|
|
|
|
+ } else {
|
|
|
|
+ conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fw_ddb_entry->iscsi_name[0]) {
|
|
|
|
+ rc = iscsi_switch_str_param(&sess->targetname,
|
|
|
|
+ (char *)fw_ddb_entry->iscsi_name);
|
|
|
|
+ if (rc)
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fw_ddb_entry->iscsi_alias[0]) {
|
|
|
|
+ rc = iscsi_switch_str_param(&sess->targetalias,
|
|
|
|
+ (char *)fw_ddb_entry->iscsi_alias);
|
|
|
|
+ if (rc)
|
|
|
|
+ goto exit_copy;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ COPY_ISID(sess->isid, fw_ddb_entry->isid);
|
|
|
|
+
|
|
|
|
+exit_copy:
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *conn,
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry)
|
|
|
|
+{
|
|
|
|
+ uint16_t options;
|
|
|
|
+ int rc = 0;
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->options);
|
|
|
|
+ SET_BITVAL(conn->is_fw_assigned_ipv6, options, BIT_11);
|
|
|
|
+ if (!strncmp(sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ options |= BIT_8;
|
|
|
|
+ else
|
|
|
|
+ options &= ~BIT_8;
|
|
|
|
+
|
|
|
|
+ SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
|
|
|
|
+ SET_BITVAL(sess->discovery_sess, options, BIT_4);
|
|
|
|
+ SET_BITVAL(sess->entry_state, options, BIT_3);
|
|
|
|
+ fw_ddb_entry->options = cpu_to_le16(options);
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
|
|
|
|
+ SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
|
|
|
|
+ SET_BITVAL(conn->datadgst_en, options, BIT_12);
|
|
|
|
+ SET_BITVAL(sess->imm_data_en, options, BIT_11);
|
|
|
|
+ SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
|
|
|
|
+ SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
|
|
|
|
+ SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
|
|
|
|
+ SET_BITVAL(sess->chap_auth_en, options, BIT_7);
|
|
|
|
+ SET_BITVAL(conn->snack_req_en, options, BIT_6);
|
|
|
|
+ SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
|
|
|
|
+ SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
|
|
|
|
+ SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
|
|
|
|
+ SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
|
|
|
|
+ SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
|
|
|
|
+ fw_ddb_entry->iscsi_options = cpu_to_le16(options);
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
|
|
|
|
+ SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
|
|
|
|
+ SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
|
|
|
|
+ SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
|
|
|
|
+ SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
|
|
|
|
+ SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
|
|
|
|
+ SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
|
|
|
|
+ SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
|
|
|
|
+ fw_ddb_entry->tcp_options = cpu_to_le16(options);
|
|
|
|
+
|
|
|
|
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
|
|
|
|
+ SET_BITVAL(conn->fragment_disable, options, BIT_4);
|
|
|
|
+ fw_ddb_entry->ip_options = cpu_to_le16(options);
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
|
|
|
|
+ fw_ddb_entry->iscsi_max_rcv_data_seg_len =
|
|
|
|
+ cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
|
|
|
|
+ fw_ddb_entry->iscsi_max_snd_data_seg_len =
|
|
|
|
+ cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
|
|
|
|
+ fw_ddb_entry->iscsi_first_burst_len =
|
|
|
|
+ cpu_to_le16(sess->first_burst / BYTE_UNITS);
|
|
|
|
+ fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
|
|
|
|
+ BYTE_UNITS);
|
|
|
|
+ fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
|
|
|
|
+ fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
|
|
|
|
+ fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
|
|
|
|
+ fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
|
|
|
|
+ fw_ddb_entry->tcp_xmt_wsf = cpu_to_le16(conn->tcp_xmit_wsf);
|
|
|
|
+ fw_ddb_entry->tcp_rcv_wsf = cpu_to_le16(conn->tcp_recv_wsf);
|
|
|
|
+ fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
|
|
|
|
+ fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
|
|
|
|
+ fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
|
|
|
|
+ fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
|
|
|
|
+ fw_ddb_entry->stat_sn = cpu_to_le16(conn->statsn);
|
|
|
|
+ fw_ddb_entry->exp_stat_sn = cpu_to_le16(conn->exp_statsn);
|
|
|
|
+ fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_type);
|
|
|
|
+ fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
|
|
|
|
+ fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
|
|
|
|
+ fw_ddb_entry->port = cpu_to_le16(conn->port);
|
|
|
|
+ fw_ddb_entry->def_timeout =
|
|
|
|
+ cpu_to_le16(sess->default_taskmgmt_timeout);
|
|
|
|
+
|
|
|
|
+ if (conn->ipaddress)
|
|
|
|
+ memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
|
|
|
|
+ sizeof(fw_ddb_entry->ip_addr));
|
|
|
|
+
|
|
|
|
+ if (conn->redirect_ipaddr)
|
|
|
|
+ memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
|
|
|
|
+ sizeof(fw_ddb_entry->tgt_addr));
|
|
|
|
+
|
|
|
|
+ if (conn->link_local_ipv6_addr)
|
|
|
|
+ memcpy(fw_ddb_entry->link_local_ipv6_addr,
|
|
|
|
+ conn->link_local_ipv6_addr,
|
|
|
|
+ sizeof(fw_ddb_entry->link_local_ipv6_addr));
|
|
|
|
+
|
|
|
|
+ if (sess->targetname)
|
|
|
|
+ memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
|
|
|
|
+ sizeof(fw_ddb_entry->iscsi_name));
|
|
|
|
+
|
|
|
|
+ if (sess->targetalias)
|
|
|
|
+ memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
|
|
|
|
+ sizeof(fw_ddb_entry->iscsi_alias));
|
|
|
|
+
|
|
|
|
+ COPY_ISID(fw_ddb_entry->isid, sess->isid);
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
|
|
static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
|
|
struct dev_db_entry *fw_ddb_entry,
|
|
struct dev_db_entry *fw_ddb_entry,
|
|
struct iscsi_cls_session *cls_sess,
|
|
struct iscsi_cls_session *cls_sess,
|
|
@@ -5062,88 +5395,195 @@ exit_nt_list:
|
|
dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
|
|
dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
|
|
|
|
+ struct list_head *list_nt)
|
|
|
|
+{
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry;
|
|
|
|
+ dma_addr_t fw_ddb_dma;
|
|
|
|
+ int max_ddbs;
|
|
|
|
+ int fw_idx_size;
|
|
|
|
+ int ret;
|
|
|
|
+ uint32_t idx = 0, next_idx = 0;
|
|
|
|
+ uint32_t state = 0, conn_err = 0;
|
|
|
|
+ uint16_t conn_id = 0;
|
|
|
|
+ struct qla_ddb_index *nt_ddb_idx;
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
|
|
|
|
+ &fw_ddb_dma);
|
|
|
|
+ if (fw_ddb_entry == NULL) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
|
|
|
|
+ goto exit_new_nt_list;
|
|
|
|
+ }
|
|
|
|
+ max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
|
|
|
|
+ MAX_DEV_DB_ENTRIES;
|
|
|
|
+ fw_idx_size = sizeof(struct qla_ddb_index);
|
|
|
|
+
|
|
|
|
+ for (idx = 0; idx < max_ddbs; idx = next_idx) {
|
|
|
|
+ ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
|
|
|
|
+ NULL, &next_idx, &state,
|
|
|
|
+ &conn_err, NULL, &conn_id);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ /* Check if NT, then add it to list */
|
|
|
|
+ if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
|
|
|
|
+ goto continue_next_new_nt;
|
|
|
|
+
|
|
|
|
+ if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
|
|
|
|
+ goto continue_next_new_nt;
|
|
|
|
+
|
|
|
|
+ DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "Adding DDB to session = 0x%x\n", idx));
|
|
|
|
+
|
|
|
|
+ nt_ddb_idx = vmalloc(fw_idx_size);
|
|
|
|
+ if (!nt_ddb_idx)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ nt_ddb_idx->fw_ddb_idx = idx;
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_is_session_exists(ha, fw_ddb_entry);
|
|
|
|
+ if (ret == QLA_SUCCESS) {
|
|
|
|
+ /* free nt_ddb_idx and do not add to list_nt */
|
|
|
|
+ vfree(nt_ddb_idx);
|
|
|
|
+ goto continue_next_new_nt;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ list_add_tail(&nt_ddb_idx->list, list_nt);
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
|
|
|
|
+ idx);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ goto exit_new_nt_list;
|
|
|
|
+
|
|
|
|
+continue_next_new_nt:
|
|
|
|
+ if (next_idx == 0)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+exit_new_nt_list:
|
|
|
|
+ if (fw_ddb_entry)
|
|
|
|
+ dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * qla4xxx_build_ddb_list - Build ddb list and setup sessions
|
|
|
|
- * @ha: pointer to adapter structure
|
|
|
|
- * @is_reset: Is this init path or reset path
|
|
|
|
|
|
+ * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
|
|
|
|
+ * @dev: dev associated with the sysfs entry
|
|
|
|
+ * @data: pointer to flashnode session object
|
|
*
|
|
*
|
|
- * Create a list of sendtargets (st) from firmware DDBs, issue send targets
|
|
|
|
- * using connection open, then create the list of normal targets (nt)
|
|
|
|
- * from firmware DDBs. Based on the list of nt setup session and connection
|
|
|
|
- * objects.
|
|
|
|
|
|
+ * Returns:
|
|
|
|
+ * 1: if flashnode entry is non-persistent
|
|
|
|
+ * 0: if flashnode entry is persistent
|
|
**/
|
|
**/
|
|
-void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
|
|
|
|
|
|
+static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
|
|
{
|
|
{
|
|
- uint16_t tmo = 0;
|
|
|
|
- struct list_head list_st, list_nt;
|
|
|
|
- struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp;
|
|
|
|
- unsigned long wtime;
|
|
|
|
|
|
+ struct iscsi_bus_flash_session *fnode_sess;
|
|
|
|
|
|
- if (!test_bit(AF_LINK_UP, &ha->flags)) {
|
|
|
|
- set_bit(AF_BUILD_DDB_LIST, &ha->flags);
|
|
|
|
- ha->is_reset = is_reset;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!iscsi_flashnode_bus_match(dev, NULL))
|
|
|
|
+ return 0;
|
|
|
|
|
|
- INIT_LIST_HEAD(&list_st);
|
|
|
|
- INIT_LIST_HEAD(&list_nt);
|
|
|
|
|
|
+ fnode_sess = iscsi_dev_to_flash_session(dev);
|
|
|
|
|
|
- qla4xxx_build_st_list(ha, &list_st);
|
|
|
|
|
|
+ return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
|
|
|
|
+}
|
|
|
|
|
|
- /* Before issuing conn open mbox, ensure all IPs states are configured
|
|
|
|
- * Note, conn open fails if IPs are not configured
|
|
|
|
- */
|
|
|
|
- qla4xxx_wait_for_ip_configuration(ha);
|
|
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
|
|
|
|
+ * @ha: pointer to host
|
|
|
|
+ * @fw_ddb_entry: flash ddb data
|
|
|
|
+ * @idx: target index
|
|
|
|
+ * @user: if set then this call is made from userland else from kernel
|
|
|
|
+ *
|
|
|
|
+ * Returns:
|
|
|
|
+ * On sucess: QLA_SUCCESS
|
|
|
|
+ * On failure: QLA_ERROR
|
|
|
|
+ *
|
|
|
|
+ * This create separate sysfs entries for session and connection attributes of
|
|
|
|
+ * the given fw ddb entry.
|
|
|
|
+ * If this is invoked as a result of a userspace call then the entry is marked
|
|
|
|
+ * as nonpersistent using flash_state field.
|
|
|
|
+ **/
|
|
|
|
+int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry,
|
|
|
|
+ uint16_t *idx, int user)
|
|
|
|
+{
|
|
|
|
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn = NULL;
|
|
|
|
+ int rc = QLA_ERROR;
|
|
|
|
|
|
- /* Go thru the STs and fire the sendtargets by issuing conn open mbx */
|
|
|
|
- list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
|
|
|
|
- qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
|
|
|
|
|
|
+ fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
|
|
|
|
+ &qla4xxx_iscsi_transport, 0);
|
|
|
|
+ if (!fnode_sess) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
|
|
|
|
+ __func__, *idx, ha->host_no);
|
|
|
|
+ goto exit_tgt_create;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Wait to ensure all sendtargets are done for min 12 sec wait */
|
|
|
|
- tmo = ((ha->def_timeout > LOGIN_TOV) &&
|
|
|
|
- (ha->def_timeout < LOGIN_TOV * 10) ?
|
|
|
|
- ha->def_timeout : LOGIN_TOV);
|
|
|
|
|
|
+ fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
|
|
|
|
+ &qla4xxx_iscsi_transport, 0);
|
|
|
|
+ if (!fnode_conn) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
|
|
|
|
+ __func__, *idx, ha->host_no);
|
|
|
|
+ goto free_sess;
|
|
|
|
+ }
|
|
|
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
- "Default time to wait for build ddb %d\n", tmo));
|
|
|
|
|
|
+ if (user) {
|
|
|
|
+ fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
|
|
|
|
+ } else {
|
|
|
|
+ fnode_sess->flash_state = DEV_DB_PERSISTENT;
|
|
|
|
|
|
- wtime = jiffies + (HZ * tmo);
|
|
|
|
- do {
|
|
|
|
- if (list_empty(&list_st))
|
|
|
|
- break;
|
|
|
|
|
|
+ if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
|
|
|
|
+ fnode_sess->is_boot_target = 1;
|
|
|
|
+ else
|
|
|
|
+ fnode_sess->is_boot_target = 0;
|
|
|
|
+ }
|
|
|
|
|
|
- qla4xxx_remove_failed_ddb(ha, &list_st);
|
|
|
|
- schedule_timeout_uninterruptible(HZ / 10);
|
|
|
|
- } while (time_after(wtime, jiffies));
|
|
|
|
|
|
+ rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
|
|
|
|
+ fw_ddb_entry);
|
|
|
|
|
|
- /* Free up the sendtargets list */
|
|
|
|
- qla4xxx_free_ddb_list(&list_st);
|
|
|
|
|
|
+ ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
|
|
|
|
+ __func__, fnode_sess->dev.kobj.name);
|
|
|
|
|
|
- qla4xxx_build_nt_list(ha, &list_nt, is_reset);
|
|
|
|
|
|
+ ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
|
|
|
|
+ __func__, fnode_conn->dev.kobj.name);
|
|
|
|
|
|
- qla4xxx_free_ddb_list(&list_nt);
|
|
|
|
|
|
+ return QLA_SUCCESS;
|
|
|
|
|
|
- qla4xxx_free_ddb_index(ha);
|
|
|
|
|
|
+free_sess:
|
|
|
|
+ iscsi_destroy_flashnode_sess(fnode_sess);
|
|
|
|
+
|
|
|
|
+exit_tgt_create:
|
|
|
|
+ return QLA_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * qla4xxx_wait_login_resp_boot_tgt - Wait for iSCSI boot target login
|
|
|
|
- * response.
|
|
|
|
- * @ha: pointer to adapter structure
|
|
|
|
|
|
+ * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
|
|
|
|
+ * @shost: pointer to host
|
|
|
|
+ * @buf: type of ddb entry (ipv4/ipv6)
|
|
|
|
+ * @len: length of buf
|
|
*
|
|
*
|
|
- * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be
|
|
|
|
- * set in DDB and we will wait for login response of boot targets during
|
|
|
|
- * probe.
|
|
|
|
|
|
+ * This creates new ddb entry in the flash by finding first free index and
|
|
|
|
+ * storing default ddb there. And then create sysfs entry for the new ddb entry.
|
|
**/
|
|
**/
|
|
-static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
|
|
|
|
|
|
+static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
|
|
|
|
+ int len)
|
|
{
|
|
{
|
|
- struct ddb_entry *ddb_entry;
|
|
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
struct dev_db_entry *fw_ddb_entry = NULL;
|
|
struct dev_db_entry *fw_ddb_entry = NULL;
|
|
dma_addr_t fw_ddb_entry_dma;
|
|
dma_addr_t fw_ddb_entry_dma;
|
|
- unsigned long wtime;
|
|
|
|
- uint32_t ddb_state;
|
|
|
|
- int max_ddbs, idx, ret;
|
|
|
|
|
|
+ struct device *dev;
|
|
|
|
+ uint16_t idx = 0;
|
|
|
|
+ uint16_t max_ddbs = 0;
|
|
|
|
+ uint32_t options = 0;
|
|
|
|
+ uint32_t rval = QLA_ERROR;
|
|
|
|
+
|
|
|
|
+ if (strncasecmp(DEV_TYPE_IPV4, buf, 4) &&
|
|
|
|
+ strncasecmp(DEV_TYPE_IPV6, buf, 4)) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
|
|
|
|
+ __func__));
|
|
|
|
+ goto exit_ddb_add;
|
|
|
|
+ }
|
|
|
|
|
|
max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
|
|
max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
|
|
MAX_DEV_DB_ENTRIES;
|
|
MAX_DEV_DB_ENTRIES;
|
|
@@ -5151,76 +5591,1278 @@ static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
|
|
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
&fw_ddb_entry_dma, GFP_KERNEL);
|
|
&fw_ddb_entry_dma, GFP_KERNEL);
|
|
if (!fw_ddb_entry) {
|
|
if (!fw_ddb_entry) {
|
|
- ql4_printk(KERN_ERR, ha,
|
|
|
|
- "%s: Unable to allocate dma buffer\n", __func__);
|
|
|
|
- goto exit_login_resp;
|
|
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ goto exit_ddb_add;
|
|
}
|
|
}
|
|
|
|
|
|
- wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV);
|
|
|
|
|
|
+ dev = iscsi_find_flashnode_sess(ha->host, NULL,
|
|
|
|
+ qla4xxx_sysfs_ddb_is_non_persistent);
|
|
|
|
+ if (dev) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: A non-persistent entry %s found\n",
|
|
|
|
+ __func__, dev->kobj.name);
|
|
|
|
+ goto exit_ddb_add;
|
|
|
|
+ }
|
|
|
|
|
|
for (idx = 0; idx < max_ddbs; idx++) {
|
|
for (idx = 0; idx < max_ddbs; idx++) {
|
|
- ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
|
|
|
|
- if (ddb_entry == NULL)
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
|
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
- "%s: DDB index [%d]\n", __func__,
|
|
|
|
- ddb_entry->fw_ddb_index));
|
|
|
|
- do {
|
|
|
|
- ret = qla4xxx_get_fwddb_entry(ha,
|
|
|
|
- ddb_entry->fw_ddb_index,
|
|
|
|
- fw_ddb_entry, fw_ddb_entry_dma,
|
|
|
|
- NULL, NULL, &ddb_state, NULL,
|
|
|
|
- NULL, NULL);
|
|
|
|
- if (ret == QLA_ERROR)
|
|
|
|
- goto exit_login_resp;
|
|
|
|
|
|
+ if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
|
|
|
|
+ fw_ddb_entry_dma, idx))
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
|
|
- if ((ddb_state == DDB_DS_SESSION_ACTIVE) ||
|
|
|
|
- (ddb_state == DDB_DS_SESSION_FAILED))
|
|
|
|
- break;
|
|
|
|
|
|
+ if (idx == max_ddbs)
|
|
|
|
+ goto exit_ddb_add;
|
|
|
|
|
|
- schedule_timeout_uninterruptible(HZ);
|
|
|
|
|
|
+ if (!strncasecmp("ipv6", buf, 4))
|
|
|
|
+ options |= IPV6_DEFAULT_DDB_ENTRY;
|
|
|
|
|
|
- } while ((time_after(wtime, jiffies)));
|
|
|
|
|
|
+ rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
|
|
|
|
+ if (rval == QLA_ERROR)
|
|
|
|
+ goto exit_ddb_add;
|
|
|
|
|
|
- if (!time_after(wtime, jiffies)) {
|
|
|
|
- DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
- "%s: Login response wait timer expired\n",
|
|
|
|
- __func__));
|
|
|
|
- goto exit_login_resp;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
|
|
|
|
|
|
-exit_login_resp:
|
|
|
|
|
|
+exit_ddb_add:
|
|
if (fw_ddb_entry)
|
|
if (fw_ddb_entry)
|
|
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
fw_ddb_entry, fw_ddb_entry_dma);
|
|
fw_ddb_entry, fw_ddb_entry_dma);
|
|
|
|
+ if (rval == QLA_SUCCESS)
|
|
|
|
+ return idx;
|
|
|
|
+ else
|
|
|
|
+ return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * qla4xxx_probe_adapter - callback function to probe HBA
|
|
|
|
- * @pdev: pointer to pci_dev structure
|
|
|
|
- * @pci_device_id: pointer to pci_device entry
|
|
|
|
|
|
+ * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
|
|
|
|
+ * @fnode_sess: pointer to session attrs of flash ddb entry
|
|
|
|
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
|
|
*
|
|
*
|
|
- * This routine will probe for Qlogic 4xxx iSCSI host adapters.
|
|
|
|
- * It returns zero if successful. It also initializes all data necessary for
|
|
|
|
- * the driver.
|
|
|
|
|
|
+ * This writes the contents of target ddb buffer to Flash with a valid cookie
|
|
|
|
+ * value in order to make the ddb entry persistent.
|
|
**/
|
|
**/
|
|
-static int qla4xxx_probe_adapter(struct pci_dev *pdev,
|
|
|
|
- const struct pci_device_id *ent)
|
|
|
|
|
|
+static int qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn)
|
|
{
|
|
{
|
|
- int ret = -ENODEV, status;
|
|
|
|
- struct Scsi_Host *host;
|
|
|
|
- struct scsi_qla_host *ha;
|
|
|
|
- uint8_t init_retry_count = 0;
|
|
|
|
- char buf[34];
|
|
|
|
- struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
|
|
|
|
- uint32_t dev_state;
|
|
|
|
|
|
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
|
|
+ uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_entry_dma;
|
|
|
|
+ uint32_t options = 0;
|
|
|
|
+ int rval = 0;
|
|
|
|
|
|
- if (pci_enable_device(pdev))
|
|
|
|
- return -1;
|
|
|
|
|
|
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ &fw_ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!fw_ddb_entry) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ rval = -ENOMEM;
|
|
|
|
+ goto exit_ddb_apply;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!strncasecmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ options |= IPV6_DEFAULT_DDB_ENTRY;
|
|
|
|
+
|
|
|
|
+ rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
|
|
|
|
+ if (rval == QLA_ERROR)
|
|
|
|
+ goto exit_ddb_apply;
|
|
|
|
+
|
|
|
|
+ dev_db_start_offset += (fnode_sess->target_id *
|
|
|
|
+ sizeof(*fw_ddb_entry));
|
|
|
|
+
|
|
|
|
+ qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
|
|
|
|
+ fw_ddb_entry->cookie = DDB_VALID_COOKIE;
|
|
|
|
+
|
|
|
|
+ rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
|
|
|
|
+ sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
|
|
|
|
+
|
|
|
|
+ if (rval == QLA_SUCCESS) {
|
|
|
|
+ fnode_sess->flash_state = DEV_DB_PERSISTENT;
|
|
|
|
+ ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "%s: flash node %u of host %lu written to flash\n",
|
|
|
|
+ __func__, fnode_sess->target_id, ha->host_no);
|
|
|
|
+ } else {
|
|
|
|
+ rval = -EIO;
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Error while writing flash node %u of host %lu to flash\n",
|
|
|
|
+ __func__, fnode_sess->target_id, ha->host_no);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+exit_ddb_apply:
|
|
|
|
+ if (fw_ddb_entry)
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ fw_ddb_entry, fw_ddb_entry_dma);
|
|
|
|
+ return rval;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry,
|
|
|
|
+ uint16_t idx)
|
|
|
|
+{
|
|
|
|
+ struct dev_db_entry *ddb_entry = NULL;
|
|
|
|
+ dma_addr_t ddb_entry_dma;
|
|
|
|
+ unsigned long wtime;
|
|
|
|
+ uint32_t mbx_sts = 0;
|
|
|
|
+ uint32_t state = 0, conn_err = 0;
|
|
|
|
+ uint16_t tmo = 0;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
|
|
|
|
+ &ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!ddb_entry) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ return QLA_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
|
|
|
|
+ if (ret != QLA_SUCCESS) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to set ddb entry for index %d\n",
|
|
|
|
+ __func__, idx));
|
|
|
|
+ goto exit_ddb_conn_open;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ qla4xxx_conn_open(ha, idx);
|
|
|
|
+
|
|
|
|
+ /* To ensure that sendtargets is done, wait for at least 12 secs */
|
|
|
|
+ tmo = ((ha->def_timeout > LOGIN_TOV) &&
|
|
|
|
+ (ha->def_timeout < LOGIN_TOV * 10) ?
|
|
|
|
+ ha->def_timeout : LOGIN_TOV);
|
|
|
|
+
|
|
|
|
+ DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "Default time to wait for login to ddb %d\n", tmo));
|
|
|
|
+
|
|
|
|
+ wtime = jiffies + (HZ * tmo);
|
|
|
|
+ do {
|
|
|
|
+ ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
|
|
|
|
+ NULL, &state, &conn_err, NULL,
|
|
|
|
+ NULL);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
|
|
|
|
+ state == DDB_DS_SESSION_FAILED)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ schedule_timeout_uninterruptible(HZ / 10);
|
|
|
|
+ } while (time_after(wtime, jiffies));
|
|
|
|
+
|
|
|
|
+exit_ddb_conn_open:
|
|
|
|
+ if (ddb_entry)
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
|
|
|
|
+ ddb_entry, ddb_entry_dma);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry)
|
|
|
|
+{
|
|
|
|
+ struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
|
|
|
|
+ struct list_head list_nt;
|
|
|
|
+ uint16_t ddb_index;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
|
|
|
|
+ ql4_printk(KERN_WARNING, ha,
|
|
|
|
+ "%s: A discovery already in progress!\n", __func__);
|
|
|
|
+ return QLA_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ INIT_LIST_HEAD(&list_nt);
|
|
|
|
+
|
|
|
|
+ set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_get_ddb_index(ha, &ddb_index);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ goto exit_login_st_clr_bit;
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ goto exit_login_st;
|
|
|
|
+
|
|
|
|
+ qla4xxx_build_new_nt_list(ha, &list_nt);
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
|
|
|
|
+ list_del_init(&ddb_idx->list);
|
|
|
|
+ qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
|
|
|
|
+ vfree(ddb_idx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+exit_login_st:
|
|
|
|
+ if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "Unable to clear DDB index = 0x%x\n", ddb_index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clear_bit(ddb_index, ha->ddb_idx_map);
|
|
|
|
+
|
|
|
|
+exit_login_st_clr_bit:
|
|
|
|
+ clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry,
|
|
|
|
+ uint16_t idx)
|
|
|
|
+{
|
|
|
|
+ int ret = QLA_ERROR;
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_is_session_exists(ha, fw_ddb_entry);
|
|
|
|
+ if (ret != QLA_SUCCESS)
|
|
|
|
+ ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
|
|
|
|
+ idx);
|
|
|
|
+ else
|
|
|
|
+ ret = -EPERM;
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_login - Login to the specified target
|
|
|
|
+ * @fnode_sess: pointer to session attrs of flash ddb entry
|
|
|
|
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
|
|
|
|
+ *
|
|
|
|
+ * This logs in to the specified target
|
|
|
|
+ **/
|
|
|
|
+static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn)
|
|
|
|
+{
|
|
|
|
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_entry_dma;
|
|
|
|
+ uint32_t options = 0;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Target info is not persistent\n", __func__);
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto exit_ddb_login;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ &fw_ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!fw_ddb_entry) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto exit_ddb_login;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!strncasecmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ options |= IPV6_DEFAULT_DDB_ENTRY;
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ goto exit_ddb_login;
|
|
|
|
+
|
|
|
|
+ qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
|
|
|
|
+ fw_ddb_entry->cookie = DDB_VALID_COOKIE;
|
|
|
|
+
|
|
|
|
+ if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
|
|
|
|
+ ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry);
|
|
|
|
+ else
|
|
|
|
+ ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
|
|
|
|
+ fnode_sess->target_id);
|
|
|
|
+
|
|
|
|
+ if (ret > 0)
|
|
|
|
+ ret = -EIO;
|
|
|
|
+
|
|
|
|
+exit_ddb_login:
|
|
|
|
+ if (fw_ddb_entry)
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ fw_ddb_entry, fw_ddb_entry_dma);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
|
|
|
|
+ * @cls_sess: pointer to session to be logged out
|
|
|
|
+ *
|
|
|
|
+ * This performs session log out from the specified target
|
|
|
|
+ **/
|
|
|
|
+static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
|
|
|
|
+{
|
|
|
|
+ struct iscsi_session *sess;
|
|
|
|
+ struct ddb_entry *ddb_entry = NULL;
|
|
|
|
+ struct scsi_qla_host *ha;
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_entry_dma;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ unsigned long wtime;
|
|
|
|
+ uint32_t ddb_state;
|
|
|
|
+ int options;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ sess = cls_sess->dd_data;
|
|
|
|
+ ddb_entry = sess->dd_data;
|
|
|
|
+ ha = ddb_entry->ha;
|
|
|
|
+
|
|
|
|
+ if (ddb_entry->ddb_type != FLASH_DDB) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
|
|
|
|
+ __func__);
|
|
|
|
+ ret = -ENXIO;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ options = LOGOUT_OPTION_CLOSE_SESSION;
|
|
|
|
+ if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ &fw_ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!fw_ddb_entry) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n", __func__);
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ wtime = jiffies + (HZ * LOGOUT_TOV);
|
|
|
|
+ do {
|
|
|
|
+ ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
|
|
|
|
+ fw_ddb_entry, fw_ddb_entry_dma,
|
|
|
|
+ NULL, NULL, &ddb_state, NULL,
|
|
|
|
+ NULL, NULL);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ goto ddb_logout_clr_sess;
|
|
|
|
+
|
|
|
|
+ if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
|
|
|
|
+ (ddb_state == DDB_DS_SESSION_FAILED))
|
|
|
|
+ goto ddb_logout_clr_sess;
|
|
|
|
+
|
|
|
|
+ schedule_timeout_uninterruptible(HZ);
|
|
|
|
+ } while ((time_after(wtime, jiffies)));
|
|
|
|
+
|
|
|
|
+ddb_logout_clr_sess:
|
|
|
|
+ qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
|
|
|
|
+ /*
|
|
|
|
+ * we have decremented the reference count of the driver
|
|
|
|
+ * when we setup the session to have the driver unload
|
|
|
|
+ * to be seamless without actually destroying the
|
|
|
|
+ * session
|
|
|
|
+ **/
|
|
|
|
+ try_module_get(qla4xxx_iscsi_transport.owner);
|
|
|
|
+ iscsi_destroy_endpoint(ddb_entry->conn->ep);
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
+ qla4xxx_free_ddb(ha, ddb_entry);
|
|
|
|
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
+
|
|
|
|
+ iscsi_session_teardown(ddb_entry->sess);
|
|
|
|
+
|
|
|
|
+ ret = QLA_SUCCESS;
|
|
|
|
+
|
|
|
|
+exit_ddb_logout:
|
|
|
|
+ if (fw_ddb_entry)
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ fw_ddb_entry, fw_ddb_entry_dma);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_logout - Logout from the specified target
|
|
|
|
+ * @fnode_sess: pointer to session attrs of flash ddb entry
|
|
|
|
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
|
|
|
|
+ *
|
|
|
|
+ * This performs log out from the specified target
|
|
|
|
+ **/
|
|
|
|
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn)
|
|
|
|
+{
|
|
|
|
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
|
|
+ struct ql4_tuple_ddb *flash_tddb = NULL;
|
|
|
|
+ struct ql4_tuple_ddb *tmp_tddb = NULL;
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ struct ddb_entry *ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_dma;
|
|
|
|
+ uint32_t next_idx = 0;
|
|
|
|
+ uint32_t state = 0, conn_err = 0;
|
|
|
|
+ uint16_t conn_id = 0;
|
|
|
|
+ int idx, index;
|
|
|
|
+ int status, ret = 0;
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
|
|
|
|
+ &fw_ddb_dma);
|
|
|
|
+ if (fw_ddb_entry == NULL) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ flash_tddb = vzalloc(sizeof(*flash_tddb));
|
|
|
|
+ if (!flash_tddb) {
|
|
|
|
+ ql4_printk(KERN_WARNING, ha,
|
|
|
|
+ "%s:Memory Allocation failed.\n", __func__);
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tmp_tddb = vzalloc(sizeof(*tmp_tddb));
|
|
|
|
+ if (!tmp_tddb) {
|
|
|
|
+ ql4_printk(KERN_WARNING, ha,
|
|
|
|
+ "%s:Memory Allocation failed.\n", __func__);
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!fnode_sess->targetname) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s:Cannot logout from SendTarget entry\n",
|
|
|
|
+ __func__);
|
|
|
|
+ ret = -EPERM;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fnode_sess->is_boot_target) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Logout from boot target entry is not permitted.\n",
|
|
|
|
+ __func__);
|
|
|
|
+ ret = -EPERM;
|
|
|
|
+ goto exit_ddb_logout;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ strncpy(flash_tddb->iscsi_name, fnode_sess->targetname,
|
|
|
|
+ ISCSI_NAME_SIZE);
|
|
|
|
+
|
|
|
|
+ if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
|
|
|
|
+ else
|
|
|
|
+ sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
|
|
|
|
+
|
|
|
|
+ flash_tddb->tpgt = fnode_sess->tpgt;
|
|
|
|
+ flash_tddb->port = fnode_conn->port;
|
|
|
|
+
|
|
|
|
+ COPY_ISID(flash_tddb->isid, fnode_sess->isid);
|
|
|
|
+
|
|
|
|
+ for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
|
|
|
|
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
|
|
|
|
+ if (ddb_entry == NULL)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (ddb_entry->ddb_type != FLASH_DDB)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ index = ddb_entry->sess->target_id;
|
|
|
|
+ status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
|
|
|
|
+ fw_ddb_dma, NULL, &next_idx,
|
|
|
|
+ &state, &conn_err, NULL,
|
|
|
|
+ &conn_id);
|
|
|
|
+ if (status == QLA_ERROR) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
|
|
|
|
+
|
|
|
|
+ status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
|
|
|
|
+ true);
|
|
|
|
+ if (status == QLA_SUCCESS) {
|
|
|
|
+ ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (idx == MAX_DDB_ENTRIES)
|
|
|
|
+ ret = -ESRCH;
|
|
|
|
+
|
|
|
|
+exit_ddb_logout:
|
|
|
|
+ if (flash_tddb)
|
|
|
|
+ vfree(flash_tddb);
|
|
|
|
+ if (tmp_tddb)
|
|
|
|
+ vfree(tmp_tddb);
|
|
|
|
+ if (fw_ddb_entry)
|
|
|
|
+ dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ int param, char *buf)
|
|
|
|
+{
|
|
|
|
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn;
|
|
|
|
+ struct ql4_chap_table chap_tbl;
|
|
|
|
+ struct device *dev;
|
|
|
|
+ int parent_type, parent_index = 0xffff;
|
|
|
|
+ int rc = 0;
|
|
|
|
+
|
|
|
|
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
|
|
|
|
+ iscsi_is_flashnode_conn_dev);
|
|
|
|
+ if (!dev)
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
|
|
|
|
+
|
|
|
|
+ switch (param) {
|
|
|
|
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
|
|
|
|
+ rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ENTRY_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PDU_INORDER:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ERL:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->erl);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_FIRST_BURST:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_R2T:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ISID:
|
|
|
|
+ rc = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
|
|
|
|
+ fnode_sess->isid[0], fnode_sess->isid[1],
|
|
|
|
+ fnode_sess->isid[2], fnode_sess->isid[3],
|
|
|
|
+ fnode_sess->isid[4], fnode_sess->isid[5]);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TSID:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->tsid);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PORT:
|
|
|
|
+ rc = sprintf(buf, "%d\n", fnode_conn->port);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_BURST:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
|
|
|
|
+ rc = sprintf(buf, "%u\n",
|
|
|
|
+ fnode_sess->default_taskmgmt_timeout);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPADDR:
|
|
|
|
+ if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
|
|
|
|
+ else
|
|
|
|
+ rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ALIAS:
|
|
|
|
+ if (fnode_sess->targetalias)
|
|
|
|
+ rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
|
|
|
|
+ else
|
|
|
|
+ rc = sprintf(buf, "\n");
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
|
|
|
|
+ if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ rc = sprintf(buf, "%pI6\n",
|
|
|
|
+ fnode_conn->redirect_ipaddr);
|
|
|
|
+ else
|
|
|
|
+ rc = sprintf(buf, "%pI4\n",
|
|
|
|
+ fnode_conn->redirect_ipaddr);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_LOCAL_PORT:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->local_port);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPV4_TOS:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPV6_TC:
|
|
|
|
+ if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ rc = sprintf(buf, "%u\n",
|
|
|
|
+ fnode_conn->ipv6_traffic_class);
|
|
|
|
+ else
|
|
|
|
+ rc = sprintf(buf, "\n");
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
|
|
|
|
+ if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4))
|
|
|
|
+ rc = sprintf(buf, "%pI6\n",
|
|
|
|
+ fnode_conn->link_local_ipv6_addr);
|
|
|
|
+ else
|
|
|
|
+ rc = sprintf(buf, "\n");
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
|
|
|
|
+ if ((fnode_sess->discovery_parent_idx) >= 0 &&
|
|
|
|
+ (fnode_sess->discovery_parent_idx < MAX_DDB_ENTRIES))
|
|
|
|
+ parent_index = fnode_sess->discovery_parent_idx;
|
|
|
|
+
|
|
|
|
+ rc = sprintf(buf, "%u\n", parent_index);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
|
|
|
|
+ if (fnode_sess->discovery_parent_type == DDB_ISNS)
|
|
|
|
+ parent_type = ISCSI_DISC_PARENT_ISNS;
|
|
|
|
+ else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
|
|
|
|
+ parent_type = ISCSI_DISC_PARENT_UNKNOWN;
|
|
|
|
+ else if (fnode_sess->discovery_parent_type >= 0 &&
|
|
|
|
+ fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
|
|
|
|
+ parent_type = ISCSI_DISC_PARENT_SENDTGT;
|
|
|
|
+ else
|
|
|
|
+ parent_type = ISCSI_DISC_PARENT_UNKNOWN;
|
|
|
|
+
|
|
|
|
+ rc = sprintf(buf, "%s\n",
|
|
|
|
+ iscsi_get_discovery_parent_name(parent_type));
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_NAME:
|
|
|
|
+ if (fnode_sess->targetname)
|
|
|
|
+ rc = sprintf(buf, "%s\n", fnode_sess->targetname);
|
|
|
|
+ else
|
|
|
|
+ rc = sprintf(buf, "\n");
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TPGT:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_CHAP_OUT_IDX:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_USERNAME:
|
|
|
|
+ if (fnode_sess->chap_auth_en) {
|
|
|
|
+ qla4xxx_get_uni_chap_at_index(ha,
|
|
|
|
+ chap_tbl.name,
|
|
|
|
+ chap_tbl.secret,
|
|
|
|
+ fnode_sess->chap_out_idx);
|
|
|
|
+ rc = sprintf(buf, "%s\n", chap_tbl.name);
|
|
|
|
+ } else {
|
|
|
|
+ rc = sprintf(buf, "\n");
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PASSWORD:
|
|
|
|
+ if (fnode_sess->chap_auth_en) {
|
|
|
|
+ qla4xxx_get_uni_chap_at_index(ha,
|
|
|
|
+ chap_tbl.name,
|
|
|
|
+ chap_tbl.secret,
|
|
|
|
+ fnode_sess->chap_out_idx);
|
|
|
|
+ rc = sprintf(buf, "%s\n", chap_tbl.secret);
|
|
|
|
+ } else {
|
|
|
|
+ rc = sprintf(buf, "\n");
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_STATSN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->statsn);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_EXP_STATSN:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IS_BOOT_TGT:
|
|
|
|
+ rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ rc = -ENOSYS;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
|
|
|
|
+ * @fnode_sess: pointer to session attrs of flash ddb entry
|
|
|
|
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
|
|
|
|
+ * @data: Parameters and their values to update
|
|
|
|
+ * @len: len of data
|
|
|
|
+ *
|
|
|
|
+ * This sets the parameter of flash ddb entry and writes them to flash
|
|
|
|
+ **/
|
|
|
|
+static int
|
|
|
|
+qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
|
|
|
|
+ struct iscsi_bus_flash_conn *fnode_conn,
|
|
|
|
+ void *data, int len)
|
|
|
|
+{
|
|
|
|
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
|
|
+ struct nlattr *attr;
|
|
|
|
+ int rc = QLA_ERROR;
|
|
|
|
+ uint32_t rem = len;
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = kzalloc(sizeof(*fw_ddb_entry), GFP_KERNEL);
|
|
|
|
+ if (!fw_ddb_entry) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate ddb buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ nla_for_each_attr(attr, data, len, rem) {
|
|
|
|
+ fnode_param = nla_data(attr);
|
|
|
|
+
|
|
|
|
+ switch (fnode_param->param) {
|
|
|
|
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
|
|
|
|
+ fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
|
|
|
|
+ memcpy(fnode_sess->portal_type, fnode_param->value,
|
|
|
|
+ strlen(fnode_sess->portal_type));
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
|
|
|
|
+ fnode_sess->auto_snd_tgt_disable =
|
|
|
|
+ fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
|
|
|
|
+ fnode_sess->discovery_sess = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ENTRY_EN:
|
|
|
|
+ fnode_sess->entry_state = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
|
|
|
|
+ fnode_conn->hdrdgst_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
|
|
|
|
+ fnode_conn->datadgst_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
|
|
|
|
+ fnode_sess->imm_data_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
|
|
|
|
+ fnode_sess->initial_r2t_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
|
|
|
|
+ fnode_sess->dataseq_inorder_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PDU_INORDER:
|
|
|
|
+ fnode_sess->pdu_inorder_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
|
|
|
|
+ fnode_sess->chap_auth_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
|
|
|
|
+ fnode_conn->snack_req_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
|
|
|
|
+ fnode_sess->discovery_logout_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
|
|
|
|
+ fnode_sess->bidi_chap_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
|
|
|
|
+ fnode_sess->discovery_auth_optional =
|
|
|
|
+ fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ERL:
|
|
|
|
+ fnode_sess->erl = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
|
|
|
|
+ fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
|
|
|
|
+ fnode_conn->tcp_nagle_disable = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
|
|
|
|
+ fnode_conn->tcp_wsf_disable = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
|
|
|
|
+ fnode_conn->tcp_timer_scale = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
|
|
|
|
+ fnode_conn->tcp_timestamp_en = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
|
|
|
|
+ fnode_conn->fragment_disable = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
|
|
|
|
+ fnode_conn->max_recv_dlength =
|
|
|
|
+ *(unsigned *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
|
|
|
|
+ fnode_conn->max_xmit_dlength =
|
|
|
|
+ *(unsigned *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_FIRST_BURST:
|
|
|
|
+ fnode_sess->first_burst =
|
|
|
|
+ *(unsigned *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
|
|
|
|
+ fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
|
|
|
|
+ fnode_sess->time2retain =
|
|
|
|
+ *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_R2T:
|
|
|
|
+ fnode_sess->max_r2t =
|
|
|
|
+ *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
|
|
|
|
+ fnode_conn->keepalive_timeout =
|
|
|
|
+ *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ISID:
|
|
|
|
+ memcpy(fnode_sess->isid, fnode_param->value,
|
|
|
|
+ sizeof(fnode_sess->isid));
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TSID:
|
|
|
|
+ fnode_sess->tsid = *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_PORT:
|
|
|
|
+ fnode_conn->port = *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_BURST:
|
|
|
|
+ fnode_sess->max_burst = *(unsigned *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
|
|
|
|
+ fnode_sess->default_taskmgmt_timeout =
|
|
|
|
+ *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPADDR:
|
|
|
|
+ memcpy(fnode_conn->ipaddress, fnode_param->value,
|
|
|
|
+ IPv6_ADDR_LEN);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_ALIAS:
|
|
|
|
+ rc = iscsi_switch_str_param(&fnode_sess->targetalias,
|
|
|
|
+ (char *)fnode_param->value);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
|
|
|
|
+ memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
|
|
|
|
+ IPv6_ADDR_LEN);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
|
|
|
|
+ fnode_conn->max_segment_size =
|
|
|
|
+ *(unsigned *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_LOCAL_PORT:
|
|
|
|
+ fnode_conn->local_port =
|
|
|
|
+ *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPV4_TOS:
|
|
|
|
+ fnode_conn->ipv4_tos = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPV6_TC:
|
|
|
|
+ fnode_conn->ipv6_traffic_class = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
|
|
|
|
+ fnode_conn->ipv6_flow_label = fnode_param->value[0];
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_NAME:
|
|
|
|
+ rc = iscsi_switch_str_param(&fnode_sess->targetname,
|
|
|
|
+ (char *)fnode_param->value);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TPGT:
|
|
|
|
+ fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
|
|
|
|
+ memcpy(fnode_conn->link_local_ipv6_addr,
|
|
|
|
+ fnode_param->value, IPv6_ADDR_LEN);
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
|
|
|
|
+ fnode_sess->discovery_parent_type =
|
|
|
|
+ *(uint16_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
|
|
|
|
+ fnode_conn->tcp_xmit_wsf =
|
|
|
|
+ *(uint8_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
|
|
|
|
+ fnode_conn->tcp_recv_wsf =
|
|
|
|
+ *(uint8_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_STATSN:
|
|
|
|
+ fnode_conn->statsn = *(uint32_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ case ISCSI_FLASHNODE_EXP_STATSN:
|
|
|
|
+ fnode_conn->exp_statsn =
|
|
|
|
+ *(uint32_t *)fnode_param->value;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: No such sysfs attribute\n", __func__);
|
|
|
|
+ rc = -ENOSYS;
|
|
|
|
+ goto exit_set_param;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
|
|
|
|
+
|
|
|
|
+exit_set_param:
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
|
|
|
|
+ * @fnode_sess: pointer to session attrs of flash ddb entry
|
|
|
|
+ *
|
|
|
|
+ * This invalidates the flash ddb entry at the given index
|
|
|
|
+ **/
|
|
|
|
+static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
|
|
|
|
+{
|
|
|
|
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
|
|
|
|
+ struct scsi_qla_host *ha = to_qla_host(shost);
|
|
|
|
+ uint32_t dev_db_start_offset;
|
|
|
|
+ uint32_t dev_db_end_offset;
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_entry_dma;
|
|
|
|
+ uint16_t *ddb_cookie = NULL;
|
|
|
|
+ int target_id;
|
|
|
|
+ int rc = 0;
|
|
|
|
+
|
|
|
|
+ if (!fnode_sess) {
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto exit_ddb_del;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fnode_sess->is_boot_target) {
|
|
|
|
+ rc = -EPERM;
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Deletion of boot target entry is not permitted.\n",
|
|
|
|
+ __func__));
|
|
|
|
+ goto exit_ddb_del;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
|
|
|
|
+ goto sysfs_ddb_del;
|
|
|
|
+
|
|
|
|
+ ddb_cookie = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_cookie),
|
|
|
|
+ &fw_ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!ddb_cookie) {
|
|
|
|
+ rc = -ENOMEM;
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ goto exit_ddb_del;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (is_qla40XX(ha)) {
|
|
|
|
+ dev_db_start_offset = FLASH_OFFSET_DB_INFO;
|
|
|
|
+ } else {
|
|
|
|
+ dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
|
|
|
|
+ (ha->hw.flt_region_ddb << 2);
|
|
|
|
+ /* flt_ddb_size is DDB table size for both ports
|
|
|
|
+ * so divide it by 2 to calculate the offset for second port
|
|
|
|
+ */
|
|
|
|
+ if (ha->port_num == 1)
|
|
|
|
+ dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev_db_end_offset = dev_db_start_offset + (ha->hw.flt_ddb_size / 2);
|
|
|
|
+ dev_db_start_offset += (fnode_sess->target_id * sizeof(*fw_ddb_entry));
|
|
|
|
+ dev_db_start_offset += (void *)&(fw_ddb_entry->cookie) -
|
|
|
|
+ (void *)fw_ddb_entry;
|
|
|
|
+
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
|
|
|
|
+ __func__, dev_db_start_offset, dev_db_end_offset));
|
|
|
|
+
|
|
|
|
+ if (dev_db_start_offset > dev_db_end_offset) {
|
|
|
|
+ rc = -EIO;
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
|
|
|
|
+ __func__, fnode_sess->target_id));
|
|
|
|
+ goto exit_ddb_del;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* invalidate the cookie */
|
|
|
|
+ *ddb_cookie = 0xFFEE;
|
|
|
|
+ qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
|
|
|
|
+ sizeof(*ddb_cookie), FLASH_OPT_RMW_COMMIT);
|
|
|
|
+
|
|
|
|
+sysfs_ddb_del:
|
|
|
|
+ target_id = fnode_sess->target_id;
|
|
|
|
+ iscsi_destroy_flashnode_sess(fnode_sess);
|
|
|
|
+ ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "%s: session and conn entries for flashnode %u of host %lu deleted\n",
|
|
|
|
+ __func__, target_id, ha->host_no);
|
|
|
|
+exit_ddb_del:
|
|
|
|
+ if (ddb_cookie)
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_cookie),
|
|
|
|
+ ddb_cookie, fw_ddb_entry_dma);
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
|
|
|
|
+ * @ha: pointer to adapter structure
|
|
|
|
+ *
|
|
|
|
+ * Export the firmware DDB for all send targets and normal targets to sysfs.
|
|
|
|
+ **/
|
|
|
|
+static int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
|
|
|
|
+{
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_entry_dma;
|
|
|
|
+ uint16_t max_ddbs;
|
|
|
|
+ uint16_t idx = 0;
|
|
|
|
+ int ret = QLA_SUCCESS;
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
|
|
|
|
+ sizeof(*fw_ddb_entry),
|
|
|
|
+ &fw_ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!fw_ddb_entry) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n",
|
|
|
|
+ __func__));
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
|
|
|
|
+ MAX_DEV_DB_ENTRIES;
|
|
|
|
+
|
|
|
|
+ for (idx = 0; idx < max_ddbs; idx++) {
|
|
|
|
+ if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
|
|
|
|
+ idx))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
|
|
|
|
+ if (ret) {
|
|
|
|
+ ret = -EIO;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
|
|
|
|
+ fw_ddb_entry_dma);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
|
|
|
|
+{
|
|
|
|
+ iscsi_destroy_all_flashnode(ha->host);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_build_ddb_list - Build ddb list and setup sessions
|
|
|
|
+ * @ha: pointer to adapter structure
|
|
|
|
+ * @is_reset: Is this init path or reset path
|
|
|
|
+ *
|
|
|
|
+ * Create a list of sendtargets (st) from firmware DDBs, issue send targets
|
|
|
|
+ * using connection open, then create the list of normal targets (nt)
|
|
|
|
+ * from firmware DDBs. Based on the list of nt setup session and connection
|
|
|
|
+ * objects.
|
|
|
|
+ **/
|
|
|
|
+void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
|
|
|
|
+{
|
|
|
|
+ uint16_t tmo = 0;
|
|
|
|
+ struct list_head list_st, list_nt;
|
|
|
|
+ struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp;
|
|
|
|
+ unsigned long wtime;
|
|
|
|
+
|
|
|
|
+ if (!test_bit(AF_LINK_UP, &ha->flags)) {
|
|
|
|
+ set_bit(AF_BUILD_DDB_LIST, &ha->flags);
|
|
|
|
+ ha->is_reset = is_reset;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ INIT_LIST_HEAD(&list_st);
|
|
|
|
+ INIT_LIST_HEAD(&list_nt);
|
|
|
|
+
|
|
|
|
+ qla4xxx_build_st_list(ha, &list_st);
|
|
|
|
+
|
|
|
|
+ /* Before issuing conn open mbox, ensure all IPs states are configured
|
|
|
|
+ * Note, conn open fails if IPs are not configured
|
|
|
|
+ */
|
|
|
|
+ qla4xxx_wait_for_ip_configuration(ha);
|
|
|
|
+
|
|
|
|
+ /* Go thru the STs and fire the sendtargets by issuing conn open mbx */
|
|
|
|
+ list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
|
|
|
|
+ qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Wait to ensure all sendtargets are done for min 12 sec wait */
|
|
|
|
+ tmo = ((ha->def_timeout > LOGIN_TOV) &&
|
|
|
|
+ (ha->def_timeout < LOGIN_TOV * 10) ?
|
|
|
|
+ ha->def_timeout : LOGIN_TOV);
|
|
|
|
+
|
|
|
|
+ DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "Default time to wait for build ddb %d\n", tmo));
|
|
|
|
+
|
|
|
|
+ wtime = jiffies + (HZ * tmo);
|
|
|
|
+ do {
|
|
|
|
+ if (list_empty(&list_st))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ qla4xxx_remove_failed_ddb(ha, &list_st);
|
|
|
|
+ schedule_timeout_uninterruptible(HZ / 10);
|
|
|
|
+ } while (time_after(wtime, jiffies));
|
|
|
|
+
|
|
|
|
+ /* Free up the sendtargets list */
|
|
|
|
+ qla4xxx_free_ddb_list(&list_st);
|
|
|
|
+
|
|
|
|
+ qla4xxx_build_nt_list(ha, &list_nt, is_reset);
|
|
|
|
+
|
|
|
|
+ qla4xxx_free_ddb_list(&list_nt);
|
|
|
|
+
|
|
|
|
+ qla4xxx_free_ddb_index(ha);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_wait_login_resp_boot_tgt - Wait for iSCSI boot target login
|
|
|
|
+ * response.
|
|
|
|
+ * @ha: pointer to adapter structure
|
|
|
|
+ *
|
|
|
|
+ * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be
|
|
|
|
+ * set in DDB and we will wait for login response of boot targets during
|
|
|
|
+ * probe.
|
|
|
|
+ **/
|
|
|
|
+static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
|
|
|
|
+{
|
|
|
|
+ struct ddb_entry *ddb_entry;
|
|
|
|
+ struct dev_db_entry *fw_ddb_entry = NULL;
|
|
|
|
+ dma_addr_t fw_ddb_entry_dma;
|
|
|
|
+ unsigned long wtime;
|
|
|
|
+ uint32_t ddb_state;
|
|
|
|
+ int max_ddbs, idx, ret;
|
|
|
|
+
|
|
|
|
+ max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
|
|
|
|
+ MAX_DEV_DB_ENTRIES;
|
|
|
|
+
|
|
|
|
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ &fw_ddb_entry_dma, GFP_KERNEL);
|
|
|
|
+ if (!fw_ddb_entry) {
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Unable to allocate dma buffer\n", __func__);
|
|
|
|
+ goto exit_login_resp;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV);
|
|
|
|
+
|
|
|
|
+ for (idx = 0; idx < max_ddbs; idx++) {
|
|
|
|
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
|
|
|
|
+ if (ddb_entry == NULL)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "%s: DDB index [%d]\n", __func__,
|
|
|
|
+ ddb_entry->fw_ddb_index));
|
|
|
|
+ do {
|
|
|
|
+ ret = qla4xxx_get_fwddb_entry(ha,
|
|
|
|
+ ddb_entry->fw_ddb_index,
|
|
|
|
+ fw_ddb_entry, fw_ddb_entry_dma,
|
|
|
|
+ NULL, NULL, &ddb_state, NULL,
|
|
|
|
+ NULL, NULL);
|
|
|
|
+ if (ret == QLA_ERROR)
|
|
|
|
+ goto exit_login_resp;
|
|
|
|
+
|
|
|
|
+ if ((ddb_state == DDB_DS_SESSION_ACTIVE) ||
|
|
|
|
+ (ddb_state == DDB_DS_SESSION_FAILED))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ schedule_timeout_uninterruptible(HZ);
|
|
|
|
+
|
|
|
|
+ } while ((time_after(wtime, jiffies)));
|
|
|
|
+
|
|
|
|
+ if (!time_after(wtime, jiffies)) {
|
|
|
|
+ DEBUG2(ql4_printk(KERN_INFO, ha,
|
|
|
|
+ "%s: Login response wait timer expired\n",
|
|
|
|
+ __func__));
|
|
|
|
+ goto exit_login_resp;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+exit_login_resp:
|
|
|
|
+ if (fw_ddb_entry)
|
|
|
|
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
|
|
|
+ fw_ddb_entry, fw_ddb_entry_dma);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * qla4xxx_probe_adapter - callback function to probe HBA
|
|
|
|
+ * @pdev: pointer to pci_dev structure
|
|
|
|
+ * @pci_device_id: pointer to pci_device entry
|
|
|
|
+ *
|
|
|
|
+ * This routine will probe for Qlogic 4xxx iSCSI host adapters.
|
|
|
|
+ * It returns zero if successful. It also initializes all data necessary for
|
|
|
|
+ * the driver.
|
|
|
|
+ **/
|
|
|
|
+static int qla4xxx_probe_adapter(struct pci_dev *pdev,
|
|
|
|
+ const struct pci_device_id *ent)
|
|
|
|
+{
|
|
|
|
+ int ret = -ENODEV, status;
|
|
|
|
+ struct Scsi_Host *host;
|
|
|
|
+ struct scsi_qla_host *ha;
|
|
|
|
+ uint8_t init_retry_count = 0;
|
|
|
|
+ char buf[34];
|
|
|
|
+ struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
|
|
|
|
+ uint32_t dev_state;
|
|
|
|
+
|
|
|
|
+ if (pci_enable_device(pdev))
|
|
|
|
+ return -1;
|
|
|
|
|
|
host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
|
|
host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
|
|
if (host == NULL) {
|
|
if (host == NULL) {
|
|
@@ -5452,6 +7094,10 @@ skip_retry_init:
|
|
ql4_printk(KERN_ERR, ha,
|
|
ql4_printk(KERN_ERR, ha,
|
|
"%s: No iSCSI boot target configured\n", __func__);
|
|
"%s: No iSCSI boot target configured\n", __func__);
|
|
|
|
|
|
|
|
+ if (qla4xxx_sysfs_ddb_export(ha))
|
|
|
|
+ ql4_printk(KERN_ERR, ha,
|
|
|
|
+ "%s: Error exporting ddb to sysfs\n", __func__);
|
|
|
|
+
|
|
/* Perform the build ddb list and login to each */
|
|
/* Perform the build ddb list and login to each */
|
|
qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
|
|
qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
|
|
iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
|
|
iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
|
|
@@ -5577,6 +7223,7 @@ static void qla4xxx_remove_adapter(struct pci_dev *pdev)
|
|
qla4xxx_destroy_fw_ddb_session(ha);
|
|
qla4xxx_destroy_fw_ddb_session(ha);
|
|
qla4_8xxx_free_sysfs_attr(ha);
|
|
qla4_8xxx_free_sysfs_attr(ha);
|
|
|
|
|
|
|
|
+ qla4xxx_sysfs_ddb_remove(ha);
|
|
scsi_remove_host(ha->host);
|
|
scsi_remove_host(ha->host);
|
|
|
|
|
|
qla4xxx_free_adapter(ha);
|
|
qla4xxx_free_adapter(ha);
|