linux/drivers/scsi/libiscsi.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * iSCSI lib functions
 *
 * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
 * Copyright (C) 2004 - 2006 Mike Christie
 * Copyright (C) 2004 - 2005 Dmitry Yusupov
 * Copyright (C) 2004 - 2005 Alex Aizman
 * maintained by [email protected]
 */
#include <linux/types.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
#include <linux/log2.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>
#include <linux/module.h>
#include <asm/unaligned.h>
#include <net/tcp.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/iscsi_proto.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/libiscsi.h>
#include <trace/events/iscsi.h>

static int iscsi_dbg_lib_conn;
module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int,
		   S_IRUGO | S_IWUSR);
MODULE_PARM_DESC();

static int iscsi_dbg_lib_session;
module_param_named(debug_libiscsi_session, iscsi_dbg_lib_session, int,
		   S_IRUGO | S_IWUSR);
MODULE_PARM_DESC();

static int iscsi_dbg_lib_eh;
module_param_named(debug_libiscsi_eh, iscsi_dbg_lib_eh, int,
		   S_IRUGO | S_IWUSR);
MODULE_PARM_DESC();

#define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...)

#define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...)

#define ISCSI_DBG_EH(_session, dbg_fmt, arg...)

#define ISCSI_CMD_COMPL_WAIT

inline void iscsi_conn_queue_xmit(struct iscsi_conn *conn)
{}
EXPORT_SYMBOL_GPL();

inline void iscsi_conn_queue_recv(struct iscsi_conn *conn)
{}
EXPORT_SYMBOL_GPL();

static void __iscsi_update_cmdsn(struct iscsi_session *session,
				 uint32_t exp_cmdsn, uint32_t max_cmdsn)
{}

void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_prep_data_out_pdu - initialize Data-Out
 * @task: scsi command task
 * @r2t: R2T info
 * @hdr: iscsi data in pdu
 *
 * Notes:
 *	Initialize Data-Out within this R2T sequence and finds
 *	proper data_offset within this SCSI command.
 *
 *	This function is called with connection lock taken.
 **/
void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t,
			   struct iscsi_data *hdr)
{}
EXPORT_SYMBOL_GPL();

static int iscsi_add_hdr(struct iscsi_task *task, unsigned len)
{}

/*
 * make an extended cdb AHS
 */
static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
{}

/**
 * iscsi_check_tmf_restrictions - check if a task is affected by TMF
 * @task: iscsi task
 * @opcode: opcode to check for
 *
 * During TMF a task has to be checked if it's affected.
 * All unrelated I/O can be passed through, but I/O to the
 * affected LUN should be restricted.
 * If 'fast_abort' is set we won't be sending any I/O to the
 * affected LUN.
 * Otherwise the target is waiting for all TTTs to be completed,
 * so we have to send all outstanding Data-Out PDUs to the target.
 */
static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
{}

/**
 * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
 * @task: iscsi task
 *
 * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
 * fields like dlength or final based on how much data it sends
 */
static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
{}

/**
 * iscsi_free_task - free a task
 * @task: iscsi cmd task
 *
 * Must be called with session back_lock.
 * This function returns the scsi command to scsi-ml or cleans
 * up mgmt tasks then returns the task to the pool.
 */
static void iscsi_free_task(struct iscsi_task *task)
{}

bool iscsi_get_task(struct iscsi_task *task)
{}
EXPORT_SYMBOL_GPL();

/**
 * __iscsi_put_task - drop the refcount on a task
 * @task: iscsi_task to drop the refcount on
 *
 * The back_lock must be held when calling in case it frees the task.
 */
void __iscsi_put_task(struct iscsi_task *task)
{}
EXPORT_SYMBOL_GPL();

void iscsi_put_task(struct iscsi_task *task)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_complete_task - finish a task
 * @task: iscsi cmd task
 * @state: state to complete task with
 *
 * Must be called with session back_lock.
 */
static void iscsi_complete_task(struct iscsi_task *task, int state)
{}

/**
 * iscsi_complete_scsi_task - finish scsi task normally
 * @task: iscsi task for scsi cmd
 * @exp_cmdsn: expected cmd sn in cpu format
 * @max_cmdsn: max cmd sn in cpu format
 *
 * This is used when drivers do not need or cannot perform
 * lower level pdu processing.
 *
 * Called with session back_lock
 */
void iscsi_complete_scsi_task(struct iscsi_task *task,
			      uint32_t exp_cmdsn, uint32_t max_cmdsn)
{}
EXPORT_SYMBOL_GPL();

/*
 * Must be called with back and frwd lock
 */
static bool cleanup_queued_task(struct iscsi_task *task)
{}

/*
 * session back and frwd lock must be held and if not called for a task that
 * is still pending or from the xmit thread, then xmit thread must be suspended
 */
static void __fail_scsi_task(struct iscsi_task *task, int err)
{}

static void fail_scsi_task(struct iscsi_task *task, int err)
{}

static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
				struct iscsi_task *task)
{}

/**
 * iscsi_alloc_mgmt_task - allocate and setup a mgmt task.
 * @conn: iscsi conn that the task will be sent on.
 * @hdr: iscsi pdu that will be sent.
 * @data: buffer for data segment if needed.
 * @data_size: length of data in bytes.
 */
static struct iscsi_task *
iscsi_alloc_mgmt_task(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
		      char *data, uint32_t data_size)
{}

/**
 * iscsi_send_mgmt_task - Send task created with iscsi_alloc_mgmt_task.
 * @task: iscsi task to send.
 *
 * On failure this returns a non-zero error code, and the driver must free
 * the task with iscsi_put_task;
 */
static int iscsi_send_mgmt_task(struct iscsi_task *task)
{}

static int __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
				 char *data, uint32_t data_size)
{}

int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
			char *data, uint32_t data_size)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_scsi_cmd_rsp - SCSI Command Response processing
 * @conn: iscsi connection
 * @hdr: iscsi header
 * @task: scsi command task
 * @data: cmd data buffer
 * @datalen: len of buffer
 *
 * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
 * then completes the command and task. called under back_lock
 **/
static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
			       struct iscsi_task *task, char *data,
			       int datalen)
{}

/**
 * iscsi_data_in_rsp - SCSI Data-In Response processing
 * @conn: iscsi connection
 * @hdr:  iscsi pdu
 * @task: scsi command task
 *
 * iscsi_data_in_rsp sets up the scsi_cmnd fields based on the data received
 * then completes the command and task. called under back_lock
 **/
static void
iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
		  struct iscsi_task *task)
{}

static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
{}

static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
{}

/**
 * iscsi_nop_out_rsp - SCSI NOP Response processing
 * @task: scsi command task
 * @nop: the nop structure
 * @data: where to put the data
 * @datalen: length of data
 *
 * iscsi_nop_out_rsp handles nop response from use or
 * from user space. called under back_lock
 **/
static int iscsi_nop_out_rsp(struct iscsi_task *task,
			     struct iscsi_nopin *nop, char *data, int datalen)
{}

static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
			       char *data, int datalen)
{}

/**
 * iscsi_itt_to_task - look up task by itt
 * @conn: iscsi connection
 * @itt: itt
 *
 * This should be used for mgmt tasks like login and nops, or if
 * the LDD's itt space does not include the session age.
 *
 * The session back_lock must be held.
 */
struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
{}
EXPORT_SYMBOL_GPL();

/**
 * __iscsi_complete_pdu - complete pdu
 * @conn: iscsi conn
 * @hdr: iscsi header
 * @data: data buffer
 * @datalen: len of data buffer
 *
 * Completes pdu processing by freeing any resources allocated at
 * queuecommand or send generic. session back_lock must be held and verify
 * itt must have been called.
 */
int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
			 char *data, int datalen)
{}
EXPORT_SYMBOL_GPL();

int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
		       char *data, int datalen)
{}
EXPORT_SYMBOL_GPL();

int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_itt_to_ctask - look up ctask by itt
 * @conn: iscsi connection
 * @itt: itt
 *
 * This should be used for cmd tasks.
 *
 * The session back_lock must be held.
 */
struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
{}
EXPORT_SYMBOL_GPL();

void iscsi_session_failure(struct iscsi_session *session,
			   enum iscsi_err err)
{}
EXPORT_SYMBOL_GPL();

static bool iscsi_set_conn_failed(struct iscsi_conn *conn)
{}

void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
{}
EXPORT_SYMBOL_GPL();

static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
{}

static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
			   bool was_requeue)
{}

/**
 * iscsi_requeue_task - requeue task to run from session workqueue
 * @task: task to requeue
 *
 * Callers must have taken a ref to the task that is going to be requeued.
 */
void iscsi_requeue_task(struct iscsi_task *task)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_data_xmit - xmit any command into the scheduled connection
 * @conn: iscsi connection
 *
 * Notes:
 *	The function can return -EAGAIN in which case the caller must
 *	re-schedule it again later or recover. '0' return code means
 *	successful xmit.
 **/
static int iscsi_data_xmit(struct iscsi_conn *conn)
{}

static void iscsi_xmitworker(struct work_struct *work)
{}

static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
						  struct scsi_cmnd *sc)
{}

enum {};

int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
{}
EXPORT_SYMBOL_GPL();

int iscsi_target_alloc(struct scsi_target *starget)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_tmf_timedout(struct timer_list *t)
{}

static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
				   struct iscsi_tm *hdr, int age,
				   int timeout)
	__must_hold(&session->frwd_lock)
{}

/*
 * Fail commands. session frwd lock held and xmit thread flushed.
 */
static void fail_scsi_tasks(struct iscsi_conn *conn, u64 lun, int error)
{}

/**
 * iscsi_suspend_queue - suspend iscsi_queuecommand
 * @conn: iscsi conn to stop queueing IO on
 *
 * This grabs the session frwd_lock to make sure no one is in
 * xmit_task/queuecommand, and then sets suspend to prevent
 * new commands from being queued. This only needs to be called
 * by offload drivers that need to sync a path like ep disconnect
 * with the iscsi_queuecommand/xmit_task. To start IO again libiscsi
 * will call iscsi_start_tx and iscsi_unblock_session when in FFP.
 */
void iscsi_suspend_queue(struct iscsi_conn *conn)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_suspend_tx - suspend iscsi_data_xmit
 * @conn: iscsi conn to stop processing IO on.
 *
 * This function sets the suspend bit to prevent iscsi_data_xmit
 * from sending new IO, and if work is queued on the xmit thread
 * it will wait for it to be completed.
 */
void iscsi_suspend_tx(struct iscsi_conn *conn)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_start_tx(struct iscsi_conn *conn)
{}

/**
 * iscsi_suspend_rx - Prevent recvwork from running again.
 * @conn: iscsi conn to stop.
 */
void iscsi_suspend_rx(struct iscsi_conn *conn)
{}
EXPORT_SYMBOL_GPL();

/*
 * We want to make sure a ping is in flight. It has timed out.
 * And we are not busy processing a pdu that is making
 * progress but got started before the ping and is taking a while
 * to complete so the ping is just stuck behind it in a queue.
 */
static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
{}

enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_check_transport_timeouts(struct timer_list *t)
{}

/**
 * iscsi_conn_unbind - prevent queueing to conn.
 * @cls_conn: iscsi conn ep is bound to.
 * @is_active: is the conn in use for boot or is this for EH/termination
 *
 * This must be called by drivers implementing the ep_disconnect callout.
 * It disables queueing to the connection from libiscsi in preparation for
 * an ep_disconnect call.
 */
void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
				      struct iscsi_tm *hdr)
{}

int iscsi_eh_abort(struct scsi_cmnd *sc)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
{}

int iscsi_eh_device_reset(struct scsi_cmnd *sc)
{}
EXPORT_SYMBOL_GPL();

void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_eh_session_reset - drop session and attempt relogin
 * @sc: scsi command
 *
 * This function will wait for a relogin, session termination from
 * userspace, or a recovery/replacement timeout.
 */
int iscsi_eh_session_reset(struct scsi_cmnd *sc)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
{}

/**
 * iscsi_eh_target_reset - reset target
 * @sc: scsi command
 *
 * This will attempt to send a warm target reset.
 */
static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
{}

/**
 * iscsi_eh_recover_target - reset target and possibly the session
 * @sc: scsi command
 *
 * This will attempt to send a warm target reset. If that fails,
 * we will escalate to ERL0 session recovery.
 */
int iscsi_eh_recover_target(struct scsi_cmnd *sc)
{}
EXPORT_SYMBOL_GPL();

/*
 * Pre-allocate a pool of @max items of @item_size. By default, the pool
 * should be accessed via kfifo_{get,put} on q->queue.
 * Optionally, the caller can obtain the array of object pointers
 * by passing in a non-NULL @items pointer
 */
int
iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
{}
EXPORT_SYMBOL_GPL();

void iscsi_pool_free(struct iscsi_pool *q)
{}
EXPORT_SYMBOL_GPL();

int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
				 uint16_t requested_cmds_max)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_host_add - add host to system
 * @shost: scsi host
 * @pdev: parent device
 *
 * This should be called by partial offload and software iscsi drivers
 * to add a host to the system.
 */
int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_host_alloc - allocate a host and driver data
 * @sht: scsi host template
 * @dd_data_size: driver host data size
 * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue
 *
 * This should be called by partial offload and software iscsi drivers.
 * To access the driver specific memory use the iscsi_host_priv() macro.
 */
struct Scsi_Host *iscsi_host_alloc(const struct scsi_host_template *sht,
				   int dd_data_size, bool xmit_can_sleep)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
{}

/**
 * iscsi_host_remove - remove host and sessions
 * @shost: scsi host
 * @is_shutdown: true if called from a driver shutdown callout
 *
 * If there are any sessions left, this will initiate the removal and wait
 * for the completion.
 */
void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown)
{}
EXPORT_SYMBOL_GPL();

void iscsi_host_free(struct Scsi_Host *shost)
{}
EXPORT_SYMBOL_GPL();

static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
{}

/**
 * iscsi_session_setup - create iscsi cls session and host and session
 * @iscsit: iscsi transport template
 * @shost: scsi host
 * @cmds_max: session can queue
 * @dd_size: private driver data size, added to session allocation size
 * @cmd_task_size: LLD task private data size
 * @initial_cmdsn: initial CmdSN
 * @id: target ID to add to this session
 *
 * This can be used by software iscsi_transports that allocate
 * a session per scsi host.
 *
 * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
 * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
 * for nop handling and login/logout requests.
 */
struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
		    uint16_t cmds_max, int dd_size, int cmd_task_size,
		    uint32_t initial_cmdsn, unsigned int id)
{}
EXPORT_SYMBOL_GPL();

/*
 * issi_session_remove - Remove session from iSCSI class.
 */
void iscsi_session_remove(struct iscsi_cls_session *cls_session)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_session_free - Free iscsi session and it's resources
 * @cls_session: iscsi session
 */
void iscsi_session_free(struct iscsi_cls_session *cls_session)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_session_teardown - destroy session and cls_session
 * @cls_session: iscsi session
 */
void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn
 * @cls_session: iscsi_cls_session
 * @dd_size: private driver data size
 * @conn_idx: cid
 */
struct iscsi_cls_conn *
iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
		 uint32_t conn_idx)
{}
EXPORT_SYMBOL_GPL();

/**
 * iscsi_conn_teardown - teardown iscsi connection
 * @cls_conn: iscsi class connection
 *
 * TODO: we may need to make this into a two step process
 * like scsi-mls remove + put host
 */
void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
{}
EXPORT_SYMBOL_GPL();

int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
{}
EXPORT_SYMBOL_GPL();

static void
fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
{}

void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
{}
EXPORT_SYMBOL_GPL();

int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
		    struct iscsi_cls_conn *cls_conn, int is_leading)
{}
EXPORT_SYMBOL_GPL();

int iscsi_switch_str_param(char **param, char *new_val_buf)
{}
EXPORT_SYMBOL_GPL();

int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
		    enum iscsi_param param, char *buf, int buflen)
{}
EXPORT_SYMBOL_GPL();

int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
			    enum iscsi_param param, char *buf)
{}
EXPORT_SYMBOL_GPL();

int iscsi_conn_get_addr_param(struct sockaddr_storage *addr,
			      enum iscsi_param param, char *buf)
{}
EXPORT_SYMBOL_GPL();

int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
			 enum iscsi_param param, char *buf)
{}
EXPORT_SYMBOL_GPL();

int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
			 char *buf)
{}
EXPORT_SYMBOL_GPL();

int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
			 char *buf, int buflen)
{}
EXPORT_SYMBOL_GPL();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();