static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req) { struct iser_conn *iser_conn = conn->dd_data; struct ib_conn *ib_conn = &iser_conn->ib_conn; struct iscsi_session *session = conn->session; iser_dbg("req op %x flags %x\n", req->opcode, req->flags); /* check if this is the last login - going to full feature phase */ if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE) return 0; /* * Check that there is one posted recv buffer * (for the last login response). */ WARN_ON(ib_conn->post_recv_buf_count != 1); if (session->discovery_sess) { iser_info("Discovery session, re-using login RX buffer\n"); return 0; } else iser_info("Normal session, posting batch of RX %d buffers\n", iser_conn->min_posted_rx); /* Initial post receive buffers */ if (iser_post_recvm(iser_conn, iser_conn->min_posted_rx)) return -ENOMEM; return 0; }
/** * iscsi_iser_conn_stop() - stop iscsi-iser connection * @cls_conn: iscsi class connection * @flag: indicate if recover or terminate (passed as is) * * Notes: Calling iscsi_conn_stop might theoretically race with * DEVICE_REMOVAL event and dereference a previously freed RDMA device * handle, so we call it under iser the state lock to protect against * this kind of race. */ static void iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) { struct iscsi_conn *conn = cls_conn->dd_data; struct iser_conn *iser_conn = conn->dd_data; iser_info("stopping iscsi_conn: %p, iser_conn: %p\n", conn, iser_conn); /* * Userspace may have goofed up and not bound the connection or * might have only partially setup the connection. */ if (iser_conn) { mutex_lock(&iser_conn->state_mutex); iser_conn_terminate(iser_conn); iscsi_conn_stop(cls_conn, flag); /* unbind */ iser_conn->iscsi_conn = NULL; conn->dd_data = NULL; complete(&iser_conn->stop_completion); mutex_unlock(&iser_conn->state_mutex); } else { iscsi_conn_stop(cls_conn, flag); } }
static int iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) { struct iser_conn *ib_conn; int rc; ib_conn = ep->dd_data; rc = wait_event_interruptible_timeout(ib_conn->wait, ib_conn->state == ISER_CONN_UP, msecs_to_jiffies(timeout_ms)); /* if conn establishment failed, return error code to iscsi */ if (!rc && (ib_conn->state == ISER_CONN_TERMINATING || ib_conn->state == ISER_CONN_DOWN)) rc = -1; iser_info("ib conn %p rc = %d\n", ib_conn, rc); if (rc > 0) return 1; /* success, this is the equivalent of POLLOUT */ else if (!rc) return 0; /* timeout */ else return rc; /* signal */ }
int iser_assign_reg_ops(struct iser_device *device) { struct ib_device *ib_dev = device->ib_device; /* Assign function handles - based on FMR support */ if (ib_dev->alloc_fmr && ib_dev->dealloc_fmr && ib_dev->map_phys_fmr && ib_dev->unmap_fmr) { iser_info("FMR supported, using FMR for registration\n"); device->reg_ops = &fmr_ops; } else if (ib_dev->attrs.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { iser_info("FastReg supported, using FastReg for registration\n"); device->reg_ops = &fastreg_ops; device->remote_inv_sup = iser_always_reg; } else { iser_err("IB device does not support FMRs nor FastRegs, can't register memory\n"); return -1; } return 0; }
/** * iscsi_iser_conn_bind() - bind iscsi and iser connection structures * @cls_session: iscsi class session * @cls_conn: iscsi class connection * @transport_eph: transport end-point handle * @is_leading: indicate if this is the session leading connection (MCS) * * Return: zero on success, $error if iscsi_conn_bind fails and * -EINVAL in case end-point doesn't exsits anymore or iser connection * state is not UP (teardown already started). */ static int iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, int is_leading) { struct iscsi_conn *conn = cls_conn->dd_data; struct iser_conn *iser_conn; struct iscsi_endpoint *ep; int error; error = iscsi_conn_bind(cls_session, cls_conn, is_leading); if (error) return error; /* the transport ep handle comes from user space so it must be * verified against the global ib connections list */ ep = iscsi_lookup_endpoint(transport_eph); if (!ep) { iser_err("can't bind eph %llx\n", (unsigned long long)transport_eph); return -EINVAL; } iser_conn = ep->dd_data; mutex_lock(&iser_conn->state_mutex); if (iser_conn->state != ISER_CONN_UP) { error = -EINVAL; iser_err("iser_conn %p state is %d, teardown started\n", iser_conn, iser_conn->state); goto out; } error = iser_alloc_rx_descriptors(iser_conn, conn->session); if (error) goto out; /* binds the iSER connection retrieved from the previously * connected ep_handle to the iSCSI layer connection. exchanges * connection pointers */ iser_info("binding iscsi conn %p to iser_conn %p\n", conn, iser_conn); conn->dd_data = iser_conn; iser_conn->iscsi_conn = conn; out: mutex_unlock(&iser_conn->state_mutex); return error; }
static void iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) { struct iser_conn *ib_conn; ib_conn = ep->dd_data; if (ib_conn->iscsi_conn) /* * Must suspend xmit path if the ep is bound to the * iscsi_conn, so we know we are not accessing the ib_conn * when we free it. * * This may not be bound if the ep poll failed. */ iscsi_suspend_tx(ib_conn->iscsi_conn); iser_info("ib conn %p state %d\n", ib_conn, ib_conn->state); iser_conn_terminate(ib_conn); }
static int iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, int is_leading) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session; struct iser_conn *ib_conn; struct iscsi_endpoint *ep; int error; error = iscsi_conn_bind(cls_session, cls_conn, is_leading); if (error) return error; /* the transport ep handle comes from user space so it must be * verified against the global ib connections list */ ep = iscsi_lookup_endpoint(transport_eph); if (!ep) { iser_err("can't bind eph %llx\n", (unsigned long long)transport_eph); return -EINVAL; } ib_conn = ep->dd_data; session = conn->session; if (iser_alloc_rx_descriptors(ib_conn, session)) return -ENOMEM; /* binds the iSER connection retrieved from the previously * connected ep_handle to the iSCSI layer connection. exchanges * connection pointers */ iser_info("binding iscsi conn %p to ib_conn %p\n", conn, ib_conn); conn->dd_data = ib_conn; ib_conn->iscsi_conn = conn; iser_conn_get(ib_conn); /* ref iscsi/ib conn binding */ return 0; }
static struct iscsi_cls_session * iscsi_iser_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, uint32_t initial_cmdsn) { struct iscsi_cls_session *cls_session; struct iscsi_session *session; struct Scsi_Host *shost; struct iser_conn *ib_conn = NULL; shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 0); if (!shost) return NULL; shost->transportt = iscsi_iser_scsi_transport; shost->cmd_per_lun = qdepth; shost->max_lun = iscsi_max_lun; shost->max_id = 0; shost->max_channel = 0; shost->max_cmd_len = 16; /* * older userspace tools (before 2.0-870) did not pass us * the leading conn's ep so this will be NULL; */ if (ep) { ib_conn = ep->dd_data; if (ib_conn->pi_support) { u32 sig_caps = ib_conn->device->dev_attr.sig_prot_cap; scsi_host_set_prot(shost, iser_dif_prot_caps(sig_caps)); if (iser_pi_guard) scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); else scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); } } if (iscsi_host_add(shost, ep ? ib_conn->device->ib_device->dma_device : NULL)) goto free_host; if (cmds_max > ISER_DEF_XMIT_CMDS_MAX) { iser_info("cmds_max changed from %u to %u\n", cmds_max, ISER_DEF_XMIT_CMDS_MAX); cmds_max = ISER_DEF_XMIT_CMDS_MAX; } cls_session = iscsi_session_setup(&iscsi_iser_transport, shost, cmds_max, 0, sizeof(struct iscsi_iser_task), initial_cmdsn, 0); if (!cls_session) goto remove_host; session = cls_session->dd_data; shost->can_queue = session->scsi_cmds_max; return cls_session; remove_host: iscsi_host_remove(shost); free_host: iscsi_host_free(shost); return NULL; }