diff --git a/iscsi-scst/include/iscsi_scst.h b/iscsi-scst/include/iscsi_scst.h index f147db601..ce9db09d1 100644 --- a/iscsi-scst/include/iscsi_scst.h +++ b/iscsi-scst/include/iscsi_scst.h @@ -62,6 +62,13 @@ enum { key_ifmarker, key_ofmarkint, key_ifmarkint, + key_rdma_extensions, + key_target_recv_data_length, + key_initiator_recv_data_length, + key_max_ahs_length, + key_tagged_buffer_for_solicited_data_only, + key_iser_hello_required, + key_max_outstanding_unexpected_pdus, session_key_last, }; diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index f5593320c..ec05699da 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -59,6 +59,9 @@ struct iscsi_sess_params { int ifmarker; int ofmarkint; int ifmarkint; + int rdma_extensions; + int target_recv_data_length; + int initiator_recv_data_length; }; struct iscsi_tgt_params { diff --git a/iscsi-scst/kernel/param.c b/iscsi-scst/kernel/param.c index aaa476010..4a5936365 100644 --- a/iscsi-scst/kernel/param.c +++ b/iscsi-scst/kernel/param.c @@ -99,12 +99,13 @@ static void log_params(struct iscsi_sess_params *params) iscsi_get_bool_value(params->data_sequence_inorder), params->error_recovery_level); PRINT_INFO(" HeaderDigest %s, DataDigest %s, OFMarker %s, " - "IFMarker %s, OFMarkInt %d, IFMarkInt %d", + "IFMarker %s, OFMarkInt %d, IFMarkInt %d, RDMAExtensions %s", iscsi_get_digest_name(params->header_digest, hdigest_name), iscsi_get_digest_name(params->data_digest, ddigest_name), iscsi_get_bool_value(params->ofmarker), iscsi_get_bool_value(params->ifmarker), - params->ofmarkint, params->ifmarkint); + params->ofmarkint, params->ifmarkint, + iscsi_get_bool_value(params->rdma_extensions)); } /* target_mutex supposed to be locked */ @@ -136,6 +137,11 @@ static void sess_params_check(struct iscsi_kern_params_info *info) CHECK_PARAM(info, iparams, ofmarker, 0, 0); CHECK_PARAM(info, iparams, ifmarker, 0, 0); + /* iSER related parameters */ + CHECK_PARAM(info, iparams, rdma_extensions, 0, 1); + CHECK_PARAM(info, iparams, target_recv_data_length, 512, max_len); + CHECK_PARAM(info, iparams, initiator_recv_data_length, 512, max_len); + return; } @@ -164,6 +170,11 @@ static void sess_params_set(struct iscsi_sess_params *params, SET_PARAM(params, info, iparams, ifmarker); SET_PARAM(params, info, iparams, ofmarkint); SET_PARAM(params, info, iparams, ifmarkint); + + /* iSER related parameters */ + SET_PARAM(params, info, iparams, rdma_extensions); + SET_PARAM(params, info, iparams, target_recv_data_length); + SET_PARAM(params, info, iparams, initiator_recv_data_length); return; } @@ -191,6 +202,11 @@ static void sess_params_get(struct iscsi_sess_params *params, GET_PARAM(params, info, iparams, ifmarker); GET_PARAM(params, info, iparams, ofmarkint); GET_PARAM(params, info, iparams, ifmarkint); + + /* iSER related parameters */ + GET_PARAM(params, info, iparams, rdma_extensions); + GET_PARAM(params, info, iparams, target_recv_data_length); + GET_PARAM(params, info, iparams, initiator_recv_data_length); return; } diff --git a/iscsi-scst/usr/iscsi_scstd.c b/iscsi-scst/usr/iscsi_scstd.c index 00a03355c..94e13d3a8 100644 --- a/iscsi-scst/usr/iscsi_scstd.c +++ b/iscsi-scst/usr/iscsi_scstd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -199,16 +200,157 @@ static struct connection *alloc_and_init_conn(int fd) pollfd->events = POLLIN; pollfd->revents = 0; + conn_read_pdu(conn); + set_non_blocking(fd); + out: return conn; } +static int transmit_iser(int fd, bool start) +{ + int opt = start; + return ioctl(fd, RDMA_CORK, &opt, sizeof(opt)); +} + +static void create_iser_listen_socket(struct pollfd *array) +{ + struct addrinfo hints, *res, *res0; + char servname[64]; + int rc, i; + int iser_fd; + struct isert_addr_info info; + + iser_fd = create_and_open_dev("isert_scst", 1); + + poll_array[POLL_ISER_LISTEN].fd = iser_fd; + if (iser_fd != -1) { + poll_array[POLL_ISER_LISTEN].events = POLLIN; + + /* RDMAExtensions */ + session_keys[key_rdma_extensions].max = 1; + session_keys[key_rdma_extensions].local_def = 1; + } else { + poll_array[POLL_ISER_LISTEN].events = 0; + return; + } + + memset(servname, 0, sizeof(servname)); + snprintf(servname, sizeof(servname), "%d", server_port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + rc = getaddrinfo(server_address, servname, &hints, &res0); + if (rc != 0) { + log_error("Unable to get address info (%s)!", + get_error_str(rc)); + exit(1); + } + + i = 0; + for (res = res0; res && i < ISERT_MAX_PORTALS; res = res->ai_next) { + memcpy(&info.addr, res->ai_addr, res->ai_addrlen); + info.addr_len = res->ai_addrlen; + + rc = ioctl(iser_fd, SET_LISTEN_ADDR, &info); + if (rc != 0) { + log_error("Unable to set address info (%s)!", + strerror(rc)); + } + ++i; + } + + freeaddrinfo(res0); +} + +static int iser_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) +{ + struct isert_addr_info addr; + int ret; + + ret = ioctl(fd, GET_PORTAL_ADDR, &addr, sizeof(addr)); + if (ret) + return ret; + + memcpy(name, &addr.addr, addr.addr_len); + *namelen = addr.addr_len; + + return ret; +} + +static int iser_is_discovery(int fd) +{ + int val = 1; + + return ioctl(fd, DISCOVERY_SESSION, &val, sizeof(val)); +} + +static void iser_accept(int fd) +{ + char buff[256]; + int ret, conn_fd; + struct connection *conn; + char target_portal[ISCSI_PORTAL_LEN], target_portal_port[NI_MAXSERV]; + struct isert_addr_info addr; + + ret = read(fd, buff, sizeof(buff)); + if (ret == -1) + return; + + conn_fd = open(buff, O_RDWR); + if (conn_fd == -1) { + log_error("open(iser_connection) %s failed: %s\n", + buff, strerror(errno)); + return; + } + + ret = ioctl(conn_fd, GET_PORTAL_ADDR, &addr, sizeof(addr)); + if (ret) + return; + + ret = getnameinfo((struct sockaddr *)&addr, sizeof(addr), target_portal, + sizeof(target_portal), target_portal_port, + sizeof(target_portal_port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) { + log_error("Target portal getnameinfo() failed: %s!", + get_error_str(ret)); + return; + } + + conn = alloc_and_init_conn(conn_fd); + if (!conn) + return; + + conn->target_portal = strdup(target_portal); + if (conn->target_portal == NULL) { + log_error("Unable to duplicate target portal %s", target_portal); + conn_free(conn); + return; + } + + conn->transmit = transmit_iser; + conn->getsockname = iser_getsockname; + conn->is_discovery = iser_is_discovery; + conn->is_iser = true; + incoming_cnt++; + + log_info("iSER connect\n"); +} + static int transmit_sock(int fd, bool start) { int opt = start; return setsockopt(fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt)); } +static int tcp_is_discovery(int fd) +{ + return 0; +} + static void accept_connection(int listen) { union { @@ -288,6 +430,8 @@ static void accept_connection(int listen) } conn->transmit = transmit_sock; + conn->getsockname = getsockname; + conn->is_discovery = tcp_is_discovery; conn_read_pdu(conn); set_non_blocking(fd); @@ -469,6 +613,7 @@ static void event_loop(void) int res, i; create_listen_socket(poll_array + POLL_LISTEN); + create_iser_listen_socket(poll_array); poll_array[POLL_IPC].fd = ipc_fd; poll_array[POLL_IPC].events = POLLIN; @@ -542,6 +687,9 @@ static void event_loop(void) if (poll_array[POLL_SCN].revents) isns_scn_handle(0); + if (poll_array[POLL_ISER_LISTEN].revents) + iser_accept(poll_array[POLL_ISER_LISTEN].fd); + for (i = 0; i < INCOMING_MAX; i++) { struct connection *conn = incoming[i]; struct pollfd *pollfd = &poll_array[POLL_INCOMING + i]; diff --git a/iscsi-scst/usr/iscsid.c b/iscsi-scst/usr/iscsid.c index 615cec4c1..703548006 100644 --- a/iscsi-scst/usr/iscsid.c +++ b/iscsi-scst/usr/iscsid.c @@ -42,6 +42,10 @@ static struct iscsi_key login_keys[] = { {"InitiatorAlias",}, {"SessionType",}, {"TargetName",}, + {"InitiatorRecvDataSegmentLength",}, + {"MaxAHSLength",}, + {"TaggedBufferForSolicitedDataOnly",}, + {"iSERHelloRequired",}, {NULL,}, }; @@ -370,6 +374,26 @@ static void text_scan_login(struct connection *conn) } } + if (conn->is_iser) { + switch (idx) { + case key_rdma_extensions: + if (val != 1) { + login_rsp_ini_err(conn, ISCSI_STATUS_INIT_ERR); + goto out; + } + break; + case key_initial_r2t: + val = 1; + break; + case key_immediate_data: + val = 0; + break; + } + } else if (idx == key_rdma_extensions && val != 0) { + login_rsp_ini_err(conn, ISCSI_STATUS_INIT_ERR); + goto out; + } + params_check_val(session_keys, idx, &val); params_set_val(session_keys, conn->session_params, idx, &val); @@ -503,6 +527,11 @@ static void login_start(struct connection *conn) if (session_type) { if (!strcmp(session_type, "Discovery")) { + int ret = conn->is_discovery(conn->fd); + if (ret) { + login_rsp_tgt_err(conn, ISCSI_STATUS_MISSING_FIELDS); + return; + } conn->session_type = SESSION_DISCOVERY; } else if (strcmp(session_type, "Normal")) { login_rsp_ini_err(conn, ISCSI_STATUS_INV_SESSION_TYPE); diff --git a/iscsi-scst/usr/iscsid.h b/iscsi-scst/usr/iscsid.h index 2a3b4490e..eb0cbce9d 100644 --- a/iscsi-scst/usr/iscsid.h +++ b/iscsi-scst/usr/iscsid.h @@ -28,8 +28,10 @@ #include "types.h" #ifdef INSIDE_KERNEL_TREE #include +#include #else #include "iscsi_scst.h" +#include "isert_scst.h" #endif #include "iscsi_hdr.h" #include "param.h" @@ -128,7 +130,11 @@ struct connection { struct __qelem clist; + bool is_iser; + int (*transmit)(int fd, bool start); + int (*getsockname)(int fd, struct sockaddr *name, socklen_t *namelen); + int (*is_discovery)(int fd); }; #define IOSTATE_FREE 0 @@ -224,6 +230,7 @@ extern int conn_blocked; enum { POLL_LISTEN, POLL_IPC = POLL_LISTEN + LISTEN_MAX, + POLL_ISER_LISTEN, POLL_NL, POLL_ISNS, POLL_SCN_LISTEN, diff --git a/iscsi-scst/usr/param.c b/iscsi-scst/usr/param.c index 9c524cde7..420e1308f 100644 --- a/iscsi-scst/usr/param.c +++ b/iscsi-scst/usr/param.c @@ -383,5 +383,13 @@ struct iscsi_key session_keys[] = { {"IFMarker", 0, 0, 0, 0, 0, &and_ops}, {"OFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops}, {"IFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops}, + {"RDMAExtensions", 0, 0, 0, 0, 1, &and_ops}, + {"TargetRecvDataSegmentLength", 8192, -1, 512, -1, 0, &minimum_ops}, + {"InitiatorRecvDataSegmentLength", 8192, -1, 512, -1, 0, &minimum_ops}, + {"MaxAHSLength", 256, 0, 0, -1, 0, &minimum_ops}, + {"TaggedBufferForSolicitedDataOnly", 0, 0, 0, 0, 0, &and_ops}, + {"iSERHelloRequired", 0, 0, 0, 0, 0, &and_ops}, + {"MaxOutstandingUnexpectedPDUs", 0, 0, 0, -1, 0, &minimum_ops}, {NULL,}, }; + diff --git a/iscsi-scst/usr/target.c b/iscsi-scst/usr/target.c index 2d475edb1..ecc00ec6d 100644 --- a/iscsi-scst/usr/target.c +++ b/iscsi-scst/usr/target.c @@ -239,10 +239,11 @@ void target_list_build(struct connection *conn, char *target_name) char portal[NI_MAXHOST]; int family, i; - if (getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) { + if (conn->getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) { log_error("getsockname failed: %m"); return; } + family = ss1.ss_family; list_for_each_entry(target, &targets_list, tlist) {