brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · 7282555 Raw
514 lines · c
1/* SPDX-License-Identifier: GPL-2.0-or-later */2/*3 * iSCSI lib definitions4 *5 * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.6 * Copyright (C) 2004 - 2006 Mike Christie7 * Copyright (C) 2004 - 2005 Dmitry Yusupov8 * Copyright (C) 2004 - 2005 Alex Aizman9 */10#ifndef LIBISCSI_H11#define LIBISCSI_H12 13#include <linux/types.h>14#include <linux/wait.h>15#include <linux/mutex.h>16#include <linux/timer.h>17#include <linux/workqueue.h>18#include <linux/kfifo.h>19#include <linux/refcount.h>20#include <scsi/iscsi_proto.h>21#include <scsi/iscsi_if.h>22#include <scsi/scsi_cmnd.h>23#include <scsi/scsi_transport_iscsi.h>24 25struct scsi_transport_template;26struct scsi_host_template;27struct scsi_device;28struct Scsi_Host;29struct scsi_target;30struct scsi_cmnd;31struct socket;32struct iscsi_transport;33struct iscsi_cls_session;34struct iscsi_cls_conn;35struct iscsi_session;36struct iscsi_nopin;37struct device;38 39#define ISCSI_DEF_XMIT_CMDS_MAX	128	/* must be power of 2 */40#define ISCSI_MGMT_CMDS_MAX	1541 42#define ISCSI_DEF_CMD_PER_LUN	3243 44/* Task Mgmt states */45enum {46	TMF_INITIAL,47	TMF_QUEUED,48	TMF_SUCCESS,49	TMF_FAILED,50	TMF_TIMEDOUT,51	TMF_NOT_FOUND,52};53 54#define ISID_SIZE			655 56/* Connection flags */57#define ISCSI_CONN_FLAG_SUSPEND_TX	058#define ISCSI_CONN_FLAG_SUSPEND_RX	159#define ISCSI_CONN_FLAG_BOUND		260 61#define ISCSI_ITT_MASK			0x1fff62#define ISCSI_TOTAL_CMDS_MAX		409663/* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */64#define ISCSI_TOTAL_CMDS_MIN		1665#define ISCSI_AGE_SHIFT			2866#define ISCSI_AGE_MASK			0xf67 68#define ISCSI_ADDRESS_BUF_LEN		6469 70enum {71	/* this is the maximum possible storage for AHSs */72	ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +73				sizeof(struct iscsi_rlength_ahdr),74	ISCSI_DIGEST_SIZE = sizeof(__u32),75};76 77 78enum {79	ISCSI_TASK_FREE,80	ISCSI_TASK_COMPLETED,81	ISCSI_TASK_PENDING,82	ISCSI_TASK_RUNNING,83	ISCSI_TASK_ABRT_TMF,		/* aborted due to TMF */84	ISCSI_TASK_ABRT_SESS_RECOV,	/* aborted due to session recovery */85	ISCSI_TASK_REQUEUE_SCSIQ,	/* qcmd requeueing to scsi-ml */86};87 88struct iscsi_r2t_info {89	__be32			ttt;		/* copied from R2T */90	__be32			exp_statsn;	/* copied from R2T */91	uint32_t		data_length;	/* copied from R2T */92	uint32_t		data_offset;	/* copied from R2T */93	int			data_count;	/* DATA-Out payload progress */94	int			datasn;95	/* LLDs should set/update these values */96	int			sent;		/* R2T sequence progress */97};98 99struct iscsi_task {100	/*101	 * Because LLDs allocate their hdr differently, this is a pointer102	 * and length to that storage. It must be setup at session103	 * creation time.104	 */105	struct iscsi_hdr	*hdr;106	unsigned short		hdr_max;107	unsigned short		hdr_len;	/* accumulated size of hdr used */108	/* copied values in case we need to send tmfs */109	itt_t			hdr_itt;110	__be32			cmdsn;111	struct scsi_lun		lun;112 113	int			itt;		/* this ITT */114 115	unsigned		imm_count;	/* imm-data (bytes)   */116	/* offset in unsolicited stream (bytes); */117	struct iscsi_r2t_info	unsol_r2t;118	char			*data;		/* mgmt payload */119	unsigned		data_count;120	struct scsi_cmnd	*sc;		/* associated SCSI cmd*/121	struct iscsi_conn	*conn;		/* used connection    */122 123	/* data processing tracking */124	unsigned long		last_xfer;125	unsigned long		last_timeout;126	bool			have_checked_conn;127 128	/* T10 protection information */129	bool			protected;130 131	/* state set/tested under session->lock */132	int			state;133	refcount_t		refcount;134	struct list_head	running;	/* running cmd list */135	void			*dd_data;	/* driver/transport data */136};137 138static inline int iscsi_task_has_unsol_data(struct iscsi_task *task)139{140	return task->unsol_r2t.data_length > task->unsol_r2t.sent;141}142 143static inline void* iscsi_next_hdr(struct iscsi_task *task)144{145	return (void*)task->hdr + task->hdr_len;146}147 148static inline bool iscsi_task_is_completed(struct iscsi_task *task)149{150	return task->state == ISCSI_TASK_COMPLETED ||151	       task->state == ISCSI_TASK_ABRT_TMF ||152	       task->state == ISCSI_TASK_ABRT_SESS_RECOV;153}154 155/* Private data associated with struct scsi_cmnd. */156struct iscsi_cmd {157	struct iscsi_task	*task;158	int			age;159};160 161static inline struct iscsi_cmd *iscsi_cmd(struct scsi_cmnd *cmd)162{163	return scsi_cmd_priv(cmd);164}165 166/* Connection's states */167enum {168	ISCSI_CONN_INITIAL_STAGE,169	ISCSI_CONN_STARTED,170	ISCSI_CONN_STOPPED,171	ISCSI_CONN_CLEANUP_WAIT,172};173 174struct iscsi_conn {175	struct iscsi_cls_conn	*cls_conn;	/* ptr to class connection */176	void			*dd_data;	/* iscsi_transport data */177	struct iscsi_session	*session;	/* parent session */178	/*179	 * conn_stop() flag: stop to recover, stop to terminate180	 */181        int			stop_stage;182	struct timer_list	transport_timer;183	unsigned long		last_recv;184	unsigned long		last_ping;185	int			ping_timeout;186	int			recv_timeout;187	struct iscsi_task 	*ping_task;188 189	/* iSCSI connection-wide sequencing */190	uint32_t		exp_statsn;191	uint32_t		statsn;192 193	/* control data */194	int			id;		/* CID */195	int			c_stage;	/* connection state */196	/*197	 * Preallocated buffer for pdus that have data but do not198	 * originate from scsi-ml. We never have two pdus using the199	 * buffer at the same time. It is only allocated to200	 * the default max recv size because the pdus we support201	 * should always fit in this buffer202	 */203	char			*data;204	struct iscsi_task 	*login_task;	/* mtask used for login/text */205	struct iscsi_task	*task;		/* xmit task in progress */206 207	/* xmit */208	/* items must be added/deleted under frwd lock */209	struct list_head	mgmtqueue;	/* mgmt (control) xmit queue */210	struct list_head	cmdqueue;	/* data-path cmd queue */211	struct list_head	requeue;	/* tasks needing another run */212	struct work_struct	xmitwork;	/* per-conn. xmit workqueue */213	/* recv */214	struct work_struct	recvwork;215	unsigned long		flags;		/* ISCSI_CONN_FLAGs */216 217	/* negotiated params */218	unsigned		max_recv_dlength; /* initiator_max_recv_dsl*/219	unsigned		max_xmit_dlength; /* target_max_recv_dsl */220	int			hdrdgst_en;221	int			datadgst_en;222	int			ifmarker_en;223	int			ofmarker_en;224	/* values userspace uses to id a conn */225	int			persistent_port;226	char			*persistent_address;227 228	unsigned		max_segment_size;229	unsigned		tcp_xmit_wsf;230	unsigned		tcp_recv_wsf;231	uint16_t		keepalive_tmo;232	uint16_t		local_port;233	uint8_t			tcp_timestamp_stat;234	uint8_t			tcp_nagle_disable;235	uint8_t			tcp_wsf_disable;236	uint8_t			tcp_timer_scale;237	uint8_t			tcp_timestamp_en;238	uint8_t			fragment_disable;239	uint8_t			ipv4_tos;240	uint8_t			ipv6_traffic_class;241	uint8_t			ipv6_flow_label;242	uint8_t			is_fw_assigned_ipv6;243	char			*local_ipaddr;244 245	/* MIB-statistics */246	uint64_t		txdata_octets;247	uint64_t		rxdata_octets;248	uint32_t		scsicmd_pdus_cnt;249	uint32_t		dataout_pdus_cnt;250	uint32_t		scsirsp_pdus_cnt;251	uint32_t		datain_pdus_cnt;252	uint32_t		r2t_pdus_cnt;253	uint32_t		tmfcmd_pdus_cnt;254	int32_t			tmfrsp_pdus_cnt;255 256	/* custom statistics */257	uint32_t		eh_abort_cnt;258	uint32_t		fmr_unalign_cnt;259};260 261struct iscsi_pool {262	struct kfifo		queue;		/* FIFO Queue */263	void			**pool;		/* Pool of elements */264	int			max;		/* Max number of elements */265};266 267/* Session's states */268enum {269	ISCSI_STATE_FREE = 1,270	ISCSI_STATE_LOGGED_IN,271	ISCSI_STATE_FAILED,272	ISCSI_STATE_TERMINATE,273	ISCSI_STATE_IN_RECOVERY,274	ISCSI_STATE_RECOVERY_FAILED,275	ISCSI_STATE_LOGGING_OUT,276};277 278struct iscsi_session {279	struct iscsi_cls_session *cls_session;280	/*281	 * Syncs up the scsi eh thread with the iscsi eh thread when sending282	 * task management functions. This must be taken before the session283	 * and recv lock.284	 */285	struct mutex		eh_mutex;286	/* abort */287	wait_queue_head_t	ehwait;		/* used in eh_abort() */288	struct iscsi_tm		tmhdr;289	struct timer_list	tmf_timer;290	int			tmf_state;	/* see TMF_INITIAL, etc.*/291	struct iscsi_task	*running_aborted_task;292 293	/* iSCSI session-wide sequencing */294	uint32_t		cmdsn;295	uint32_t		exp_cmdsn;296	uint32_t		max_cmdsn;297 298	/* This tracks the reqs queued into the initiator */299	uint32_t		queued_cmdsn;300 301	/* configuration */302	int			abort_timeout;303	int			lu_reset_timeout;304	int			tgt_reset_timeout;305	int			initial_r2t_en;306	unsigned short		max_r2t;307	int			imm_data_en;308	unsigned		first_burst;309	unsigned		max_burst;310	int			time2wait;311	int			time2retain;312	int			pdu_inorder_en;313	int			dataseq_inorder_en;314	int			erl;315	int			fast_abort;316	int			tpgt;317	char			*username;318	char			*username_in;319	char			*password;320	char			*password_in;321	char			*targetname;322	char			*targetalias;323	char			*ifacename;324	char			*initiatorname;325	char			*boot_root;326	char			*boot_nic;327	char			*boot_target;328	char			*portal_type;329	char			*discovery_parent_type;330	uint16_t		discovery_parent_idx;331	uint16_t		def_taskmgmt_tmo;332	uint16_t		tsid;333	uint8_t			auto_snd_tgt_disable;334	uint8_t			discovery_sess;335	uint8_t			chap_auth_en;336	uint8_t			discovery_logout_en;337	uint8_t			bidi_chap_en;338	uint8_t			discovery_auth_optional;339	uint8_t			isid[ISID_SIZE];340 341	/* control data */342	struct iscsi_transport	*tt;343	struct Scsi_Host	*host;344	struct iscsi_conn	*leadconn;	/* leading connection */345	/* Between the forward and the backward locks exists a strict locking346	 * hierarchy. The mutual exclusion zone protected by the forward lock347	 * can enclose the mutual exclusion zone protected by the backward lock348	 * but not vice versa.349	 */350	spinlock_t		frwd_lock;	/* protects session state, *351						 * cmdsn, queued_cmdsn     *352						 * session resources:      *353						 * - cmdpool kfifo_out ,   *354						 * - mgmtpool, queues	   */355	spinlock_t		back_lock;	/* protects cmdsn_exp      *356						 * cmdsn_max,              *357						 * cmdpool kfifo_in        */358	int			state;		/* session state           */359	int			age;		/* counts session re-opens */360 361	int			scsi_cmds_max; 	/* max scsi commands */362	int			cmds_max;	/* size of cmds array */363	struct iscsi_task	**cmds;		/* Original Cmds arr */364	struct iscsi_pool	cmdpool;	/* PDU's pool */365	void			*dd_data;	/* LLD private data */366};367 368enum {369	ISCSI_HOST_SETUP,370	ISCSI_HOST_REMOVED,371};372 373struct iscsi_host {374	char			*initiatorname;375	/* hw address or netdev iscsi connection is bound to */376	char			*hwaddress;377	char			*netdev;378 379	wait_queue_head_t	session_removal_wq;380	/* protects sessions and state */381	spinlock_t		lock;382	int			num_sessions;383	int			state;384 385	struct workqueue_struct	*workq;386};387 388/*389 * scsi host template390 */391extern int iscsi_eh_abort(struct scsi_cmnd *sc);392extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);393extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);394extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);395extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc);396extern enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc);397 398/*399 * iSCSI host helpers.400 */401#define iscsi_host_priv(_shost) \402	(shost_priv(_shost) + sizeof(struct iscsi_host))403 404extern int iscsi_host_set_param(struct Scsi_Host *shost,405				enum iscsi_host_param param, char *buf,406				int buflen);407extern int iscsi_host_get_param(struct Scsi_Host *shost,408				enum iscsi_host_param param, char *buf);409extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);410extern struct Scsi_Host *iscsi_host_alloc(const struct scsi_host_template *sht,411					  int dd_data_size,412					  bool xmit_can_sleep);413extern void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown);414extern void iscsi_host_free(struct Scsi_Host *shost);415extern int iscsi_target_alloc(struct scsi_target *starget);416extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,417					uint16_t requested_cmds_max);418 419/*420 * session management421 */422extern struct iscsi_cls_session *423iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,424		    uint16_t, int, int, uint32_t, unsigned int);425void iscsi_session_remove(struct iscsi_cls_session *cls_session);426void iscsi_session_free(struct iscsi_cls_session *cls_session);427extern void iscsi_session_teardown(struct iscsi_cls_session *);428extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);429extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,430			   enum iscsi_param param, char *buf, int buflen);431extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,432				   enum iscsi_param param, char *buf);433 434#define iscsi_session_printk(prefix, _sess, fmt, a...)	\435	iscsi_cls_session_printk(prefix, _sess->cls_session, fmt, ##a)436 437/*438 * connection management439 */440extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *,441					       int, uint32_t);442extern void iscsi_conn_teardown(struct iscsi_cls_conn *);443extern int iscsi_conn_start(struct iscsi_cls_conn *);444extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);445extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,446			   int);447extern void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active);448extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);449extern void iscsi_session_failure(struct iscsi_session *session,450				  enum iscsi_err err);451extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,452				enum iscsi_param param, char *buf);453extern int iscsi_conn_get_addr_param(struct sockaddr_storage *addr,454				     enum iscsi_param param, char *buf);455extern void iscsi_suspend_tx(struct iscsi_conn *conn);456extern void iscsi_suspend_rx(struct iscsi_conn *conn);457extern void iscsi_suspend_queue(struct iscsi_conn *conn);458extern void iscsi_conn_queue_xmit(struct iscsi_conn *conn);459extern void iscsi_conn_queue_recv(struct iscsi_conn *conn);460 461#define iscsi_conn_printk(prefix, _c, fmt, a...) \462	iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \463			      fmt, ##a)464 465/*466 * pdu and task processing467 */468extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);469extern void iscsi_prep_data_out_pdu(struct iscsi_task *task,470				    struct iscsi_r2t_info *r2t,471				    struct iscsi_data *hdr);472extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,473				char *, uint32_t);474extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,475			      char *, int);476extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,477				char *, int);478extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);479extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);480extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);481extern void iscsi_requeue_task(struct iscsi_task *task);482extern void iscsi_put_task(struct iscsi_task *task);483extern void __iscsi_put_task(struct iscsi_task *task);484extern bool iscsi_get_task(struct iscsi_task *task);485extern void iscsi_complete_scsi_task(struct iscsi_task *task,486				     uint32_t exp_cmdsn, uint32_t max_cmdsn);487 488/*489 * generic helpers490 */491extern void iscsi_pool_free(struct iscsi_pool *);492extern int iscsi_pool_init(struct iscsi_pool *, int, void ***, int);493extern int iscsi_switch_str_param(char **, char *);494 495/*496 * inline functions to deal with padding.497 */498static inline unsigned int499iscsi_padded(unsigned int len)500{501	return (len + ISCSI_PAD_LEN - 1) & ~(ISCSI_PAD_LEN - 1);502}503 504static inline unsigned int505iscsi_padding(unsigned int len)506{507	len &= (ISCSI_PAD_LEN - 1);508	if (len)509		len = ISCSI_PAD_LEN - len;510	return len;511}512 513#endif514