📄 iscsi_iser.c
字号:
/* * iSCSI Initiator over iSER Data-Path * * Copyright (C) 2004 Dmitry Yusupov * Copyright (C) 2004 Alex Aizman * Copyright (C) 2005 Mike Christie * Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved. * maintained by openib-general@openib.org * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Credits: * Christoph Hellwig * FUJITA Tomonori * Arne Redlich * Zhenyu Wang * Modified by: * Erez Zilber * * * $Id: iscsi_iser.c 6965 2006-05-07 11:36:20Z ogerlitz $ */#include <linux/types.h>#include <linux/list.h>#include <linux/hardirq.h>#include <linux/kfifo.h>#include <linux/blkdev.h>#include <linux/init.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/in.h>#include <linux/net.h>#include <linux/scatterlist.h>#include <linux/delay.h>#include <net/sock.h>#include <asm/uaccess.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_eh.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_host.h>#include <scsi/scsi.h>#include <scsi/scsi_transport_iscsi.h>#include "iscsi_iser.h"static unsigned int iscsi_max_lun = 512;module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);int iser_debug_level = 0;MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover " "v" DRV_VER " (" DRV_DATE ")");MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz");module_param_named(debug_level, iser_debug_level, int, 0644);MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");struct iser_global ig;voidiscsi_iser_recv(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *rx_data, int rx_data_len){ int rc = 0; uint32_t ret_itt; int datalen; int ahslen; /* verify PDU length */ datalen = ntoh24(hdr->dlength); if (datalen != rx_data_len) { printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n", datalen, rx_data_len); rc = ISCSI_ERR_DATALEN; goto error; } /* read AHS */ ahslen = hdr->hlength * 4; /* verify itt (itt encoding: age+cid+itt) */ rc = iscsi_verify_itt(conn, hdr, &ret_itt); if (!rc) rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len); if (rc && rc != ISCSI_ERR_NO_SCSI_CMD) goto error; return;error: iscsi_conn_failure(conn, rc);}/** * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * **/static voidiscsi_iser_cmd_init(struct iscsi_cmd_task *ctask){ struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data; struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; iser_ctask->command_sent = 0; iser_ctask->iser_conn = iser_conn; iser_ctask_rdma_init(iser_ctask);}/** * iscsi_mtask_xmit - xmit management(immediate) task * @conn: iscsi connection * @mtask: task management task * * Notes: * The function can return -EAGAIN in which case caller must * call it again later, or recover. '0' return code means successful * xmit. * **/static intiscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask){ int error = 0; debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt); error = iser_send_control(conn, mtask); /* since iser xmits control with zero copy, mtasks can not be recycled * right after sending them. * The recycling scheme is based on whether a response is expected * - if yes, the mtask is recycled at iscsi_complete_pdu * - if no, the mtask is recycled at iser_snd_completion */ if (error && error != -ENOBUFS) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error;}static intiscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){ struct iscsi_data hdr; int error = 0; /* Send data-out PDUs while there's still unsolicited data to send */ while (ctask->unsol_count > 0) { iscsi_prep_unsolicit_data_pdu(ctask, &hdr); debug_scsi("Sending data-out: itt 0x%x, data count %d\n", hdr.itt, ctask->data_count); /* the buffer description has been passed with the command */ /* Send the command */ error = iser_send_data_out(conn, ctask, &hdr); if (error) { ctask->unsol_datasn--; goto iscsi_iser_ctask_xmit_unsol_data_exit; } ctask->unsol_count -= ctask->data_count; debug_scsi("Need to send %d more as data-out PDUs\n", ctask->unsol_count); }iscsi_iser_ctask_xmit_unsol_data_exit: return error;}static intiscsi_iser_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; int error = 0; if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { BUG_ON(scsi_bufflen(ctask->sc) == 0); debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", ctask->itt, scsi_bufflen(ctask->sc), ctask->imm_count, ctask->unsol_count); } debug_scsi("ctask deq [cid %d itt 0x%x]\n", conn->id, ctask->itt); /* * serialize with TMF AbortTask */ if (ctask->mtask) return error; /* Send the cmd PDU */ if (!iser_ctask->command_sent) { error = iser_send_command(conn, ctask); if (error) goto iscsi_iser_ctask_xmit_exit; iser_ctask->command_sent = 1; } /* Send unsolicited data-out PDU(s) if necessary */ if (ctask->unsol_count) error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask); iscsi_iser_ctask_xmit_exit: if (error && error != -ENOBUFS) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error;}static voidiscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; if (iser_ctask->status == ISER_TASK_STATUS_STARTED) { iser_ctask->status = ISER_TASK_STATUS_COMPLETED; iser_ctask_rdma_finalize(iser_ctask); }}static struct iser_conn *iscsi_iser_ib_conn_lookup(__u64 ep_handle){ struct iser_conn *ib_conn; struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle; mutex_lock(&ig.connlist_mutex); list_for_each_entry(ib_conn, &ig.connlist, conn_list) { if (ib_conn == uib_conn) { mutex_unlock(&ig.connlist_mutex); return ib_conn; } } mutex_unlock(&ig.connlist_mutex); iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle); return NULL;}static struct iscsi_cls_conn *iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx){ struct iscsi_conn *conn; struct iscsi_cls_conn *cls_conn; struct iscsi_iser_conn *iser_conn; cls_conn = iscsi_conn_setup(cls_session, conn_idx); if (!cls_conn) return NULL; conn = cls_conn->dd_data; /* * due to issues with the login code re iser sematics * this not set in iscsi_conn_setup - FIXME */ conn->max_recv_dlength = 128; iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL); if (!iser_conn) goto conn_alloc_fail; /* currently this is the only field which need to be initiated */ rwlock_init(&iser_conn->lock); conn->dd_data = iser_conn; iser_conn->iscsi_conn = conn; return cls_conn;conn_alloc_fail: iscsi_conn_teardown(cls_conn); return NULL;}static voidiscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn){ struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_iser_conn *iser_conn = conn->dd_data; iscsi_conn_teardown(cls_conn); if (iser_conn->ib_conn) iser_conn->ib_conn->iser_conn = NULL; kfree(iser_conn);}static intiscsi_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_iser_conn *iser_conn; struct iser_conn *ib_conn; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -