/* * 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. * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved. * maintained by [email protected] * * 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 */ #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 <linux/slab.h> #include <linux/module.h> #include <net/sock.h> #include <linux/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" MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; static const struct scsi_host_template iscsi_iser_sht; static struct iscsi_transport iscsi_iser_transport; static struct scsi_transport_template *iscsi_iser_scsi_transport; static struct workqueue_struct *release_wq; static DEFINE_MUTEX(unbind_iser_conn_mutex); struct iser_global ig; int iser_debug_level = …; module_param_named(debug_level, iser_debug_level, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(…) …; static int iscsi_iser_set(const char *val, const struct kernel_param *kp); static const struct kernel_param_ops iscsi_iser_size_ops = …; static unsigned int iscsi_max_lun = …; module_param_cb(…); MODULE_PARM_DESC(…) …; unsigned int iser_max_sectors = …; module_param_cb(…); MODULE_PARM_DESC(…) …; bool iser_always_reg = …; module_param_named(always_register, iser_always_reg, bool, S_IRUGO); MODULE_PARM_DESC(…) …; bool iser_pi_enable = …; module_param_named(pi_enable, iser_pi_enable, bool, S_IRUGO); MODULE_PARM_DESC(…) …; static int iscsi_iser_set(const char *val, const struct kernel_param *kp) { … } /* * iscsi_iser_recv() - Process a successful recv completion * @conn: iscsi connection * @hdr: iscsi header * @rx_data: buffer containing receive data payload * @rx_data_len: length of rx_data * * Notes: In case of data length errors or iscsi PDU completion failures * this routine will signal iscsi layer of connection failure. */ void iscsi_iser_recv(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *rx_data, int rx_data_len) { … } /** * iscsi_iser_pdu_alloc() - allocate an iscsi-iser PDU * @task: iscsi task * @opcode: iscsi command opcode * * Netes: This routine can't fail, just assign iscsi task * hdr and max hdr size. */ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode) { … } /** * iser_initialize_task_headers() - Initialize task headers * @task: iscsi task * @tx_desc: iser tx descriptor * * Notes: * This routine may race with iser teardown flow for scsi * error handling TMFs. So for TMF we should acquire the * state mutex to avoid dereferencing the IB device which * may have already been terminated. */ int iser_initialize_task_headers(struct iscsi_task *task, struct iser_tx_desc *tx_desc) { … } /** * iscsi_iser_task_init() - Initialize iscsi-iser task * @task: iscsi task * * Initialize the task for the scsi command or mgmt command. * * Return: Returns zero on success or -ENOMEM when failing * to init task headers (dma mapping error). */ static int iscsi_iser_task_init(struct iscsi_task *task) { … } /** * iscsi_iser_mtask_xmit() - xmit management (immediate) task * @conn: iscsi connection * @task: 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 int iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) { … } static int iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn, struct iscsi_task *task) { … } /** * iscsi_iser_task_xmit() - xmit iscsi-iser task * @task: iscsi task * * Return: zero on success or escalates $error on failure. */ static int iscsi_iser_task_xmit(struct iscsi_task *task) { … } /** * iscsi_iser_cleanup_task() - cleanup an iscsi-iser task * @task: iscsi task * * Notes: In case the RDMA device is already NULL (might have * been removed in DEVICE_REMOVAL CM event it will bail-out * without doing dma unmapping. */ static void iscsi_iser_cleanup_task(struct iscsi_task *task) { … } /** * iscsi_iser_check_protection() - check protection information status of task. * @task: iscsi task * @sector: error sector if exsists (output) * * Return: zero if no data-integrity errors have occured * 0x1: data-integrity error occured in the guard-block * 0x2: data-integrity error occured in the reference tag * 0x3: data-integrity error occured in the application tag * * In addition the error sector is marked. */ static u8 iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector) { … } /** * iscsi_iser_conn_create() - create a new iscsi-iser connection * @cls_session: iscsi class connection * @conn_idx: connection index within the session (for MCS) * * Return: iscsi_cls_conn when iscsi_conn_setup succeeds or NULL * otherwise. */ static struct iscsi_cls_conn * iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) { … } /** * 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 exists 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) { … } /** * iscsi_iser_conn_start() - start iscsi-iser connection * @cls_conn: iscsi class connection * * Notes: Here iser intialize (or re-initialize) stop_completion as * from this point iscsi must call conn_stop in session/connection * teardown so iser transport must wait for it. */ static int iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) { … } /** * 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) { … } /** * iscsi_iser_session_destroy() - destroy iscsi-iser session * @cls_session: iscsi class session * * Removes and free iscsi host. */ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) { … } static inline unsigned int iser_dif_prot_caps(int prot_caps) { … } /** * iscsi_iser_session_create() - create an iscsi-iser session * @ep: iscsi end-point handle * @cmds_max: maximum commands in this session * @qdepth: session command queue depth * @initial_cmdsn: initiator command sequnce number * * Allocates and adds a scsi host, expose DIF supprot if * exists, and sets up an iscsi session. */ static struct iscsi_cls_session * iscsi_iser_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, uint32_t initial_cmdsn) { … } static int iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf, int buflen) { … } /** * iscsi_iser_conn_get_stats() - get iscsi connection statistics * @cls_conn: iscsi class connection * @stats: iscsi stats to output * * Output connection statistics. */ static void iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) { … } static int iscsi_iser_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, char *buf) { … } /** * iscsi_iser_ep_connect() - Initiate iSER connection establishment * @shost: scsi_host * @dst_addr: destination address * @non_blocking: indicate if routine can block * * Allocate an iscsi endpoint, an iser_conn structure and bind them. * After that start RDMA connection establishment via rdma_cm. We * don't allocate iser_conn embedded in iscsi_endpoint since in teardown * the endpoint will be destroyed at ep_disconnect while iser_conn will * cleanup its resources asynchronuously. * * Return: iscsi_endpoint created by iscsi layer or ERR_PTR(error) * if fails. */ static struct iscsi_endpoint *iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, int non_blocking) { … } /** * iscsi_iser_ep_poll() - poll for iser connection establishment to complete * @ep: iscsi endpoint (created at ep_connect) * @timeout_ms: polling timeout allowed in ms. * * This routine boils down to waiting for up_completion signaling * that cma_id got CONNECTED event. * * Return: 1 if succeeded in connection establishment, 0 if timeout expired * (libiscsi will retry will kick in) or -1 if interrupted by signal * or more likely iser connection state transitioned to TEMINATING or * DOWN during the wait period. */ static int iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) { … } /** * iscsi_iser_ep_disconnect() - Initiate connection teardown process * @ep: iscsi endpoint handle * * This routine is not blocked by iser and RDMA termination process * completion as we queue a deffered work for iser/RDMA destruction * and cleanup or actually call it immediately in case we didn't pass * iscsi conn bind/start stage, thus it is safe. */ static void iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) { … } static umode_t iser_attr_is_visible(int param_type, int param) { … } static const struct scsi_host_template iscsi_iser_sht = …; static struct iscsi_transport iscsi_iser_transport = …; static int __init iser_init(void) { … } static void __exit iser_exit(void) { … } module_init(…) …; module_exit(iser_exit);