From 6733b39a1301b0b020bbcbf3295852e93e624cb1 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 5 Sep 2009 07:36:35 +0530 Subject: [SCSI] be2iscsi: add 10Gbps iSCSI - BladeEngine 2 driver [v2: fixed up virt_to_bus() issue spotted by sfr] Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 646 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 646 insertions(+) create mode 100644 drivers/scsi/be2iscsi/be_iscsi.c (limited to 'drivers/scsi/be2iscsi/be_iscsi.c') diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c new file mode 100644 index 000000000000..b23526cb39d7 --- /dev/null +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -0,0 +1,646 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "be_iscsi.h" + +extern struct iscsi_transport beiscsi_iscsi_transport; + +/** + * beiscsi_session_create - creates a new iscsi session + * @cmds_max: max commands supported + * @qdepth: max queue depth supported + * @initial_cmdsn: initial iscsi CMDSN + */ +struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, + u16 cmds_max, + u16 qdepth, + u32 initial_cmdsn) +{ + struct Scsi_Host *shost; + struct beiscsi_endpoint *beiscsi_ep; + struct iscsi_cls_session *cls_session; + struct iscsi_session *sess; + struct beiscsi_hba *phba; + struct iscsi_task *task; + struct beiscsi_io_task *io_task; + unsigned int max_size, num_cmd; + dma_addr_t bus_add; + u64 pa_addr; + void *vaddr; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n"); + + if (!ep) { + SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n"); + return NULL; + } + beiscsi_ep = ep->dd_data; + phba = beiscsi_ep->phba; + shost = phba->shost; + if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) { + shost_printk(KERN_ERR, shost, "Cannot handle %d cmds." + "Max cmds per session supported is %d. Using %d. " + "\n", cmds_max, + beiscsi_ep->phba->params.wrbs_per_cxn, + beiscsi_ep->phba->params.wrbs_per_cxn); + cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn; + } + + cls_session = iscsi_session_setup(&beiscsi_iscsi_transport, + shost, cmds_max, + sizeof(struct beiscsi_io_task), + initial_cmdsn, ISCSI_MAX_TARGET); + if (!cls_session) + return NULL; + sess = cls_session->dd_data; + max_size = ALIGN(sizeof(struct be_cmd_bhs), 64) * sess->cmds_max; + vaddr = pci_alloc_consistent(phba->pcidev, max_size, &bus_add); + pa_addr = (__u64) bus_add; + + for (num_cmd = 0; num_cmd < sess->cmds_max; num_cmd++) { + task = sess->cmds[num_cmd]; + io_task = task->dd_data; + io_task->cmd_bhs = vaddr; + io_task->bhs_pa.u.a64.address = pa_addr; + io_task->alloc_size = max_size; + vaddr += ALIGN(sizeof(struct be_cmd_bhs), 64); + pa_addr += ALIGN(sizeof(struct be_cmd_bhs), 64); + } + return cls_session; +} + +/** + * beiscsi_session_destroy - destroys iscsi session + * @cls_session: pointer to iscsi cls session + * + * Destroys iSCSI session instance and releases + * resources allocated for it. + */ +void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) +{ + struct iscsi_task *task; + struct beiscsi_io_task *io_task; + struct iscsi_session *sess = cls_session->dd_data; + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct beiscsi_hba *phba = iscsi_host_priv(shost); + + task = sess->cmds[0]; + io_task = task->dd_data; + pci_free_consistent(phba->pcidev, + io_task->alloc_size, + io_task->cmd_bhs, + io_task->bhs_pa.u.a64.address); + iscsi_session_teardown(cls_session); +} + +/** + * beiscsi_conn_create - create an instance of iscsi connection + * @cls_session: ptr to iscsi_cls_session + * @cid: iscsi cid + */ +struct iscsi_cls_conn * +beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) +{ + struct beiscsi_hba *phba; + struct Scsi_Host *shost; + struct iscsi_cls_conn *cls_conn; + struct beiscsi_conn *beiscsi_conn; + struct iscsi_conn *conn; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid" + "from iscsi layer=%d\n", cid); + shost = iscsi_session_to_shost(cls_session); + phba = iscsi_host_priv(shost); + + cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid); + if (!cls_conn) + return NULL; + + conn = cls_conn->dd_data; + beiscsi_conn = conn->dd_data; + beiscsi_conn->ep = NULL; + beiscsi_conn->phba = phba; + beiscsi_conn->conn = conn; + return cls_conn; +} + +/** + * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table + * @beiscsi_conn: The pointer to beiscsi_conn structure + * @phba: The phba instance + * @cid: The cid to free + */ +static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, + struct beiscsi_conn *beiscsi_conn, + unsigned int cid) +{ + if (phba->conn_table[cid]) { + SE_DEBUG(DBG_LVL_1, + "Connection table already occupied. Detected clash\n"); + return -EINVAL; + } else { + SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n", + cid, beiscsi_conn); + phba->conn_table[cid] = beiscsi_conn; + } + return 0; +} + +/** + * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection + * @cls_session: pointer to iscsi cls session + * @cls_conn: pointer to iscsi cls conn + * @transport_fd: EP handle(64 bit) + * + * This function binds the TCP Conn with iSCSI Connection and Session. + */ +int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, + struct iscsi_cls_conn *cls_conn, + u64 transport_fd, int is_leading) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct beiscsi_conn *beiscsi_conn = conn->dd_data; + struct Scsi_Host *shost = + (struct Scsi_Host *)iscsi_session_to_shost(cls_session); + struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); + struct beiscsi_endpoint *beiscsi_ep; + struct iscsi_endpoint *ep; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n"); + ep = iscsi_lookup_endpoint(transport_fd); + if (!ep) + return -EINVAL; + + beiscsi_ep = ep->dd_data; + + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) + return -EINVAL; + + if (beiscsi_ep->phba != phba) { + SE_DEBUG(DBG_LVL_8, + "beiscsi_ep->hba=%p not equal to phba=%p \n", + beiscsi_ep->phba, phba); + return -EEXIST; + } + + beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; + beiscsi_conn->ep = beiscsi_ep; + beiscsi_ep->conn = beiscsi_conn; + SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n", + beiscsi_conn, conn, beiscsi_ep->ep_cid); + return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); +} + +/** + * beiscsi_conn_get_param - get the iscsi parameter + * @cls_conn: pointer to iscsi cls conn + * @param: parameter type identifier + * @buf: buffer pointer + * + * returns iscsi parameter + */ +int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct beiscsi_endpoint *beiscsi_ep; + struct iscsi_conn *conn = cls_conn->dd_data; + struct beiscsi_conn *beiscsi_conn = conn->dd_data; + int len = 0; + + beiscsi_ep = beiscsi_conn->ep; + if (!beiscsi_ep) { + SE_DEBUG(DBG_LVL_1, + "In beiscsi_conn_get_param , no beiscsi_ep\n"); + return -1; + } + + switch (param) { + case ISCSI_PARAM_CONN_PORT: + len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport); + break; + case ISCSI_PARAM_CONN_ADDRESS: + if (beiscsi_ep->ip_type == BE2_IPV4) + len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr); + else + len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr); + break; + default: + return iscsi_conn_get_param(cls_conn, param, buf); + } + return len; +} + +int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + int ret; + + ret = iscsi_set_param(cls_conn, param, buf, buflen); + if (ret) + return ret; + /* + * If userspace tried to set the value to higher than we can + * support override here. + */ + switch (param) { + case ISCSI_PARAM_FIRST_BURST: + if (session->first_burst > 8192) + session->first_burst = 8192; + break; + case ISCSI_PARAM_MAX_RECV_DLENGTH: + if (conn->max_recv_dlength > 65536) + conn->max_recv_dlength = 65536; + break; + case ISCSI_PARAM_MAX_BURST: + if (session->first_burst > 262144) + session->first_burst = 262144; + break; + default: + return 0; + } + + return 0; +} + +/** + * beiscsi_get_host_param - get the iscsi parameter + * @shost: pointer to scsi_host structure + * @param: parameter type identifier + * @buf: buffer pointer + * + * returns host parameter + */ +int beiscsi_get_host_param(struct Scsi_Host *shost, + enum iscsi_host_param param, char *buf) +{ + struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); + int len = 0; + + switch (param) { + case ISCSI_HOST_PARAM_HWADDRESS: + be_cmd_get_mac_addr(&phba->ctrl, phba->mac_address); + len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN); + break; + default: + return iscsi_host_get_param(shost, param, buf); + } + return len; +} + +/** + * beiscsi_conn_get_stats - get the iscsi stats + * @cls_conn: pointer to iscsi cls conn + * @stats: pointer to iscsi_stats structure + * + * returns iscsi stats + */ +void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, + struct iscsi_stats *stats) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n"); + stats->txdata_octets = conn->txdata_octets; + stats->rxdata_octets = conn->rxdata_octets; + stats->dataout_pdus = conn->dataout_pdus_cnt; + stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; + stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; + stats->datain_pdus = conn->datain_pdus_cnt; + stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; + stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; + stats->r2t_pdus = conn->r2t_pdus_cnt; + stats->digest_err = 0; + stats->timeout_err = 0; + stats->custom_length = 0; + strcpy(stats->custom[0].desc, "eh_abort_cnt"); + stats->custom[0].value = conn->eh_abort_cnt; +} + +/** + * beiscsi_set_params_for_offld - get the parameters for offload + * @beiscsi_conn: pointer to beiscsi_conn + * @params: pointer to offload_params structure + */ +static void beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn, + struct beiscsi_offload_params *params) +{ + struct iscsi_conn *conn = beiscsi_conn->conn; + struct iscsi_session *session = conn->session; + + AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length, + params, session->max_burst); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, + max_send_data_segment_length, params, + conn->max_xmit_dlength); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length, + params, session->first_burst); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params, + session->erl); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params, + conn->datadgst_en); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params, + conn->hdrdgst_en); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params, + session->initial_r2t_en); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params, + session->imm_data_en); + AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params, + (conn->exp_statsn - 1)); +} + +/** + * beiscsi_conn_start - offload of session to chip + * @cls_conn: pointer to beiscsi_conn + */ +int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct beiscsi_conn *beiscsi_conn = conn->dd_data; + struct beiscsi_endpoint *beiscsi_ep; + struct beiscsi_offload_params params; + 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); + + memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); + beiscsi_ep = beiscsi_conn->ep; + if (!beiscsi_ep) + SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n"); + + free_mgmt_sgl_handle(phba, beiscsi_conn->plogin_sgl_handle); + beiscsi_conn->login_in_progress = 0; + beiscsi_set_params_for_offld(beiscsi_conn, ¶ms); + beiscsi_offload_connection(beiscsi_conn, ¶ms); + iscsi_conn_start(cls_conn); + return 0; +} + +/** + * beiscsi_get_cid - Allocate a cid + * @phba: The phba instance + */ +static int beiscsi_get_cid(struct beiscsi_hba *phba) +{ + unsigned short cid = 0xFFFF; + + if (!phba->avlbl_cids) + return cid; + + cid = phba->cid_array[phba->cid_alloc++]; + if (phba->cid_alloc == phba->params.cxns_per_ctrl) + phba->cid_alloc = 0; + phba->avlbl_cids--; + return cid; +} + +/** + * 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; + int ret = -1; + + 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 ", + beiscsi_ep->ep_cid); + phba->ep_array[beiscsi_ep->ep_cid] = ep; + if (beiscsi_ep->ep_cid > + (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) { + SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); + return ret; + } + + beiscsi_ep->cid_vld = 0; + return mgmt_open_connection(phba, dst_addr, beiscsi_ep); +} + +/** + * beiscsi_put_cid - Free the cid + * @phba: The phba for which the cid is being freed + * @cid: The cid to free + */ +static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) +{ + phba->avlbl_cids++; + phba->cid_array[phba->cid_free++] = cid; + if (phba->cid_free == phba->params.cxns_per_ctrl) + phba->cid_free = 0; +} + +/** + * beiscsi_free_ep - free endpoint + * @ep: pointer to iscsi endpoint structure + */ +static void beiscsi_free_ep(struct iscsi_endpoint *ep) +{ + struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; + struct beiscsi_hba *phba = beiscsi_ep->phba; + + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); + beiscsi_ep->phba = NULL; + iscsi_destroy_endpoint(ep); +} + +/** + * 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); + } + ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint)); + if (!ep) { + ret = -ENOMEM; + return ERR_PTR(ret); + } + + beiscsi_ep = ep->dd_data; + beiscsi_ep->phba = phba; + + if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { + SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); + ret = -ENOMEM; + goto free_ep; + } + + return ep; + +free_ep: + beiscsi_free_ep(ep); + return ERR_PTR(ret); +} + +/** + * beiscsi_ep_poll - Poll to see if connection is established + * @ep: endpoint to be used + * @timeout_ms: timeout specified in millisecs + * + * Poll to see if TCP connection established + */ +int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) +{ + struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_poll\n"); + if (beiscsi_ep->cid_vld == 1) + return 1; + else + return 0; +} + +/** + * beiscsi_close_conn - Upload the connection + * @ep: The iscsi endpoint + * @flag: The type of connection closure + */ +static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag) +{ + int ret = 0; + struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; + struct beiscsi_hba *phba = beiscsi_ep->phba; + + if (MGMT_STATUS_SUCCESS != + mgmt_upload_connection(phba, beiscsi_ep->ep_cid, + CONNECTION_UPLOAD_GRACEFUL)) { + SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", + beiscsi_ep->ep_cid); + ret = -1; + } + + return 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; + int flag = 0; + + beiscsi_ep = ep->dd_data; + phba = beiscsi_ep->phba; + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n"); + + if (beiscsi_ep->conn) { + beiscsi_conn = beiscsi_ep->conn; + iscsi_suspend_queue(beiscsi_conn->conn); + beiscsi_close_conn(ep, flag); + } + + beiscsi_free_ep(ep); +} + +/** + * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table + * @phba: The phba instance + * @cid: The cid to free + */ +static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, + unsigned int cid) +{ + if (phba->conn_table[cid]) + phba->conn_table[cid] = NULL; + else { + SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n"); + return -EINVAL; + } + return 0; +} + +/** + * 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 status; + unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n"); + beiscsi_ep = beiscsi_conn->ep; + if (!beiscsi_ep) { + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); + return; + } + status = mgmt_invalidate_connection(phba, beiscsi_ep, + beiscsi_ep->ep_cid, 1, + savecfg_flag); + if (status != MGMT_STATUS_SUCCESS) { + SE_DEBUG(DBG_LVL_1, + "mgmt_invalidate_connection Failed for cid=%d \n", + beiscsi_ep->ep_cid); + } + beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); + iscsi_conn_stop(cls_conn, flag); +} -- cgit v1.2.3 From b8b9e1b8128d8854cf55740f9ceba3010143520d Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 22 Sep 2009 08:21:22 +0530 Subject: [SCSI] libiscsi: iscsi_session_setup to allow for private space This patch contains changes that allow iscsi_session_setup to allocate private space for LLD's Signed-off-by: Jayamohan Kallickal Acked-by: Mike Christie Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/scsi/be2iscsi/be_iscsi.c | 6 ++++-- drivers/scsi/be2iscsi/be_main.h | 5 +++++ drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 2 +- drivers/scsi/iscsi_tcp.c | 2 +- drivers/scsi/libiscsi.c | 6 ++++-- include/scsi/libiscsi.h | 3 ++- 8 files changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/be2iscsi/be_iscsi.c') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 0ba6ec876296..add9188663ff 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -426,7 +426,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, * because we preallocate so many resources */ cls_session = iscsi_session_setup(&iscsi_iser_transport, shost, - ISCSI_DEF_XMIT_CMDS_MAX, + ISCSI_DEF_XMIT_CMDS_MAX, 0, sizeof(struct iscsi_iser_task), initial_cmdsn, 0); if (!cls_session) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index b23526cb39d7..f18e643f3589 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -44,9 +44,10 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, struct Scsi_Host *shost; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_cls_session *cls_session; - struct iscsi_session *sess; struct beiscsi_hba *phba; struct iscsi_task *task; + struct iscsi_session *sess; + struct beiscsi_session *beiscsi_sess; struct beiscsi_io_task *io_task; unsigned int max_size, num_cmd; dma_addr_t bus_add; @@ -73,7 +74,8 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, cls_session = iscsi_session_setup(&beiscsi_iscsi_transport, shost, cmds_max, - sizeof(struct beiscsi_io_task), + sizeof(*beiscsi_sess), + sizeof(*io_task), initial_cmdsn, ISCSI_MAX_TARGET); if (!cls_session) return NULL; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 2520c39c594d..387e363b0ec7 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -327,6 +327,10 @@ struct beiscsi_hba { struct be_ctrl_info ctrl; }; +struct beiscsi_session { + struct pci_pool *bhs_pool; +}; + /** * struct beiscsi_conn - iscsi connection structure */ @@ -338,6 +342,7 @@ struct beiscsi_conn { struct beiscsi_endpoint *ep; unsigned short login_in_progress; struct sgl_handle *plogin_sgl_handle; + struct beiscsi_session *beiscsi_sess; }; /* This structure is used by the chip */ diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 9a7ba71f1af4..cafb888c2376 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1243,7 +1243,7 @@ bnx2i_session_create(struct iscsi_endpoint *ep, cmds_max = BNX2I_SQ_WQES_MIN; cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost, - cmds_max, sizeof(struct bnx2i_cmd), + cmds_max, 0, sizeof(struct bnx2i_cmd), initial_cmdsn, ISCSI_MAX_TARGET); if (!cls_session) return NULL; diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index c399f485aa7d..2631bddd255e 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c @@ -422,7 +422,7 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth, BUG_ON(hba != iscsi_host_priv(shost)); cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost, - cmds_max, + cmds_max, 0, sizeof(struct iscsi_tcp_task) + sizeof(struct cxgb3i_task_data), initial_cmdsn, ISCSI_MAX_TARGET); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 2b1b834a098b..edc49ca49cea 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -811,7 +811,7 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, goto free_host; cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost, - cmds_max, + cmds_max, 0, sizeof(struct iscsi_tcp_task) + sizeof(struct iscsi_sw_tcp_hdrbuf), initial_cmdsn, 0); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8dc73c489a17..f1a4246f890c 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2436,7 +2436,7 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost) */ struct iscsi_cls_session * iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, - uint16_t cmds_max, int cmd_task_size, + uint16_t cmds_max, int dd_size, int cmd_task_size, uint32_t initial_cmdsn, unsigned int id) { struct iscsi_host *ihost = shost_priv(shost); @@ -2486,7 +2486,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX; cls_session = iscsi_alloc_session(shost, iscsit, - sizeof(struct iscsi_session)); + sizeof(struct iscsi_session) + + dd_size); if (!cls_session) goto dec_session_count; session = cls_session->dd_data; @@ -2503,6 +2504,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, session->max_cmdsn = initial_cmdsn + 1; session->max_r2t = 1; session->tt = iscsit; + session->dd_data = cls_session->dd_data + sizeof(*session); mutex_init(&session->eh_mutex); spin_lock_init(&session->lock); diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 887e57e3e223..a72edd4eceec 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -303,6 +303,7 @@ struct iscsi_session { int cmds_max; /* size of cmds array */ struct iscsi_task **cmds; /* Original Cmds arr */ struct iscsi_pool cmdpool; /* PDU's pool */ + void *dd_data; /* LLD private data */ }; enum { @@ -363,7 +364,7 @@ extern int iscsi_target_alloc(struct scsi_target *starget); */ extern struct iscsi_cls_session * iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost, - uint16_t, int, uint32_t, unsigned int); + uint16_t, int, int, uint32_t, unsigned int); extern void iscsi_session_teardown(struct iscsi_cls_session *); extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn, -- cgit v1.2.3 From 2afc95bf546a961d2936d886c3802e159f1bae6b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Tue, 22 Sep 2009 08:22:26 +0530 Subject: [SCSI] be2iscsi: Moving to pci_pools v3 This patch contains changes to use pci_pools for iscsi hdr instead of pci_alloc_consistent. Here we alloc and free to pool for every IO v3: - Remove cleanup loop in beiscsi_session_destroy - Fixup for allocation failure handling in beiscsi_alloc_pdu - Removed unused variable in beiscsi_session_destroy. [jejb: fix up pci_pool_alloc address sizing problem] Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 46 +++++++++++---------------- drivers/scsi/be2iscsi/be_main.c | 69 +++++++++++++++++++--------------------- drivers/scsi/be2iscsi/be_main.h | 1 - 3 files changed, 51 insertions(+), 65 deletions(-) (limited to 'drivers/scsi/be2iscsi/be_iscsi.c') diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index f18e643f3589..2fd25442cfaf 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -45,14 +45,9 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, struct beiscsi_endpoint *beiscsi_ep; struct iscsi_cls_session *cls_session; struct beiscsi_hba *phba; - struct iscsi_task *task; struct iscsi_session *sess; struct beiscsi_session *beiscsi_sess; struct beiscsi_io_task *io_task; - unsigned int max_size, num_cmd; - dma_addr_t bus_add; - u64 pa_addr; - void *vaddr; SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n"); @@ -80,20 +75,18 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, if (!cls_session) return NULL; sess = cls_session->dd_data; - max_size = ALIGN(sizeof(struct be_cmd_bhs), 64) * sess->cmds_max; - vaddr = pci_alloc_consistent(phba->pcidev, max_size, &bus_add); - pa_addr = (__u64) bus_add; - - for (num_cmd = 0; num_cmd < sess->cmds_max; num_cmd++) { - task = sess->cmds[num_cmd]; - io_task = task->dd_data; - io_task->cmd_bhs = vaddr; - io_task->bhs_pa.u.a64.address = pa_addr; - io_task->alloc_size = max_size; - vaddr += ALIGN(sizeof(struct be_cmd_bhs), 64); - pa_addr += ALIGN(sizeof(struct be_cmd_bhs), 64); - } + beiscsi_sess = sess->dd_data; + beiscsi_sess->bhs_pool = pci_pool_create("beiscsi_bhs_pool", + phba->pcidev, + sizeof(struct be_cmd_bhs), + 64, 0); + if (!beiscsi_sess->bhs_pool) + goto destroy_sess; + return cls_session; +destroy_sess: + iscsi_session_teardown(cls_session); + return NULL; } /** @@ -105,18 +98,10 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, */ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) { - struct iscsi_task *task; - struct beiscsi_io_task *io_task; struct iscsi_session *sess = cls_session->dd_data; - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct beiscsi_session *beiscsi_sess = sess->dd_data; - task = sess->cmds[0]; - io_task = task->dd_data; - pci_free_consistent(phba->pcidev, - io_task->alloc_size, - io_task->cmd_bhs, - io_task->bhs_pa.u.a64.address); + pci_pool_destroy(beiscsi_sess->bhs_pool); iscsi_session_teardown(cls_session); } @@ -133,6 +118,8 @@ beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) struct iscsi_cls_conn *cls_conn; struct beiscsi_conn *beiscsi_conn; struct iscsi_conn *conn; + struct iscsi_session *sess; + struct beiscsi_session *beiscsi_sess; SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid" "from iscsi layer=%d\n", cid); @@ -148,6 +135,9 @@ beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) beiscsi_conn->ep = NULL; beiscsi_conn->phba = phba; beiscsi_conn->conn = conn; + sess = cls_session->dd_data; + beiscsi_sess = sess->dd_data; + beiscsi_conn->beiscsi_sess = beiscsi_sess; return cls_conn; } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d520fe875859..4f1aca346e38 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2880,7 +2880,16 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; itt_t itt; + struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; + dma_addr_t paddr; + io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool, + GFP_KERNEL, &paddr); + + if (!io_task->cmd_bhs) + return -ENOMEM; + + io_task->bhs_pa.u.a64.address = paddr; io_task->pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, task->itt); @@ -2894,17 +2903,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) spin_lock(&phba->io_sgl_lock); io_task->psgl_handle = alloc_io_sgl_handle(phba); spin_unlock(&phba->io_sgl_lock); - if (!io_task->psgl_handle) { - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context - [beiscsi_conn->beiscsi_conn_cid]; - free_wrb_handle(phba, pwrb_context, - io_task->pwrb_handle); - io_task->pwrb_handle = NULL; - SE_DEBUG(DBG_LVL_1, - "Alloc of SGL_ICD Failed \n"); - return -ENOMEM; - } + if (!io_task->psgl_handle) + goto free_hndls; + } else { io_task->scsi_cmnd = NULL; if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { @@ -2913,18 +2914,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->psgl_handle = (struct sgl_handle *) alloc_mgmt_sgl_handle(phba); spin_unlock(&phba->mgmt_sgl_lock); - if (!io_task->psgl_handle) { - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = - &phwi_ctrlr->wrb_context - [beiscsi_conn->beiscsi_conn_cid]; - free_wrb_handle(phba, pwrb_context, - io_task->pwrb_handle); - io_task->pwrb_handle = NULL; - SE_DEBUG(DBG_LVL_1, "Alloc of " - "MGMT_SGL_ICD Failed \n"); - return -ENOMEM; - } + if (!io_task->psgl_handle) + goto free_hndls; + beiscsi_conn->login_in_progress = 1; beiscsi_conn->plogin_sgl_handle = io_task->psgl_handle; @@ -2936,23 +2928,24 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) spin_lock(&phba->mgmt_sgl_lock); io_task->psgl_handle = alloc_mgmt_sgl_handle(phba); spin_unlock(&phba->mgmt_sgl_lock); - if (!io_task->psgl_handle) { - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context - [beiscsi_conn->beiscsi_conn_cid]; - free_wrb_handle(phba, pwrb_context, - io_task->pwrb_handle); - io_task->pwrb_handle = NULL; - SE_DEBUG(DBG_LVL_1, "Alloc of " - "MGMT_SGL_ICD Failed \n"); - return -ENOMEM; - } + if (!io_task->psgl_handle) + goto free_hndls; } } itt = (itt_t) cpu_to_be32(((unsigned int)task->itt << 16) | (unsigned int)(io_task->psgl_handle->sgl_index)); io_task->cmd_bhs->iscsi_hdr.itt = itt; return 0; + +free_hndls: + phwi_ctrlr = phba->phwi_ctrlr; + pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); + io_task->pwrb_handle = NULL; + pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, + io_task->bhs_pa.u.a64.address); + SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n"); + return -ENOMEM; } static void beiscsi_cleanup_task(struct iscsi_task *task) @@ -2961,6 +2954,7 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) struct iscsi_conn *conn = task->conn; struct beiscsi_conn *beiscsi_conn = conn->dd_data; struct beiscsi_hba *phba = beiscsi_conn->phba; + struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; @@ -2971,6 +2965,11 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) io_task->pwrb_handle = NULL; } + if (io_task->cmd_bhs) { + pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, + io_task->bhs_pa.u.a64.address); + } + if (task->sc) { if (io_task->psgl_handle) { spin_lock(&phba->io_sgl_lock); @@ -3003,7 +3002,6 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, unsigned int doorbell = 0; pwrb = io_task->pwrb_handle->pwrb; - io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0; io_task->bhs_len = sizeof(struct be_cmd_bhs); @@ -3020,7 +3018,6 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, &io_task->cmd_bhs->iscsi_data_pdu, 1); AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); - } else { SE_DEBUG(DBG_LVL_4, "READ Command \t"); AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 387e363b0ec7..53c9b70ac7ac 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -391,7 +391,6 @@ struct beiscsi_io_task { unsigned short cid; unsigned short header_len; - unsigned int alloc_size; struct be_cmd_bhs *cmd_bhs; struct be_bus_address bhs_pa; unsigned short bhs_len; -- cgit v1.2.3