/** * beiscsi_ep_connect - Ask chip to create TCP Conn * @scsi_host: Pointer to scsi_host structure * @dst_addr: The IP address of Target * @non_blocking: blocking or non-blocking call * * This routines first asks chip to create a connection and then allocates an EP */ struct iscsi_endpoint * beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, int non_blocking) { struct beiscsi_hba *phba; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; int ret; SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n"); if (shost) phba = iscsi_host_priv(shost); else { ret = -ENXIO; SE_DEBUG(DBG_LVL_1, "shost is NULL \n"); return ERR_PTR(ret); } if (phba->state != BE_ADAPTER_UP) { ret = -EBUSY; SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); return ERR_PTR(ret); } ep = iscsi2_create_endpoint(sizeof(struct beiscsi_endpoint)); if (!ep) { ret = -ENOMEM; return ERR_PTR(ret); } beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; beiscsi_ep->openiscsi_ep = ep; if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); ret = -ENOMEM; goto free_ep; } return ep; free_ep: beiscsi_free_ep(beiscsi_ep); return ERR_PTR(ret); }
/** * beiscsi_ep_disconnect - Tears down the TCP connection * @ep: endpoint to be used * * Tears down the TCP connection */ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) { struct beiscsi_conn *beiscsi_conn; struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_hba *phba; unsigned int tag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", beiscsi_ep->ep_cid); if (!beiscsi_ep->conn) { SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no " "beiscsi_ep\n"); return; } beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n", beiscsi_ep->ep_cid); tag = mgmt_invalidate_connection(phba, beiscsi_ep, beiscsi_ep->ep_cid, 1, savecfg_flag); if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_invalidate_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); beiscsi_free_ep(beiscsi_ep); beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); }
/** * beiscsi_conn_stop - Invalidate and stop the connection * @cls_conn: pointer to get iscsi_conn * @flag: The type of connection closure */ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) { struct iscsi_conn *conn = cls_conn->dd_data; struct beiscsi_conn *beiscsi_conn = conn->dd_data; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_session *session = conn->session; struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); struct beiscsi_hba *phba = iscsi_host_priv(shost); unsigned int tag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); return; } SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n", beiscsi_ep->ep_cid); tag = mgmt_invalidate_connection(phba, beiscsi_ep, beiscsi_ep->ep_cid, 0, savecfg_flag); if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_invalidate_connection Failed for cid=%d \n", beiscsi_ep->ep_cid); } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); beiscsi_free_ep(beiscsi_ep); iscsi2_destroy_endpoint(beiscsi_ep->openiscsi_ep); SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop for ep_cid = %d\n", beiscsi_ep->ep_cid); beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); iscsi2_conn_stop(cls_conn, flag); }
/** * beiscsi_open_conn - Ask FW to open a TCP connection * @ep: endpoint to be used * @src_addr: The source IP address * @dst_addr: The Destination IP address * * Asks the FW to open a TCP connection */ static int beiscsi_open_conn(struct iscsi_endpoint *ep, struct sockaddr *src_addr, struct sockaddr *dst_addr, int non_blocking) { struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; struct be_mcc_wrb *wrb; struct tcp_connect_and_offload_out *ptcpcnct_out; unsigned short status, extd_status; struct be_dma_mem nonemb_cmd; unsigned int tag, wrb_num; int ret = -ENOMEM; SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); if (beiscsi_ep->ep_cid == 0xFFFF) { SE_DEBUG(DBG_LVL_1, "No free cid available\n"); return ret; } SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d\n", beiscsi_ep->ep_cid); phba->ep_array[beiscsi_ep->ep_cid - phba->fw_config.iscsi_cid_start] = ep; if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl * 2)) { SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); goto free_ep; } beiscsi_ep->cid_vld = 0; nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, sizeof(struct tcp_connect_and_offload_in), &nonemb_cmd.dma); if (nonemb_cmd.va == NULL) { SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for mgmt_open_connection" "\n"); beiscsi_put_cid(phba, beiscsi_ep->ep_cid); return -ENOMEM; } nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in); memset(nonemb_cmd.va, 0, nonemb_cmd.size); tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd); if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); beiscsi_put_cid(phba, beiscsi_ep->ep_cid); pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return -EAGAIN; } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); } wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; if (status || extd_status) { SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" " status = %d extd_status = %d\n", status, extd_status); free_mcc_tag(&phba->ctrl, tag); pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); goto free_ep; } else { wrb = queue_get_wrb(mccq, wrb_num); free_mcc_tag(&phba->ctrl, tag); ptcpcnct_out = embedded_payload(wrb); beiscsi_ep = ep->dd_data; beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; beiscsi_ep->cid_vld = 1; SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); } pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return 0; free_ep: beiscsi_free_ep(beiscsi_ep); return -EBUSY; }