Files
scst/iscsi-scst/kernel/iscsi.h
Vladislav Bolkhovitin bc96b052d5 The patch below adds support for the 2.6.29 kernel and also fixes the
checkpatch issues reported by the checkpatch script included with the 2.6.29
kernel and that were not yet reported by the 2.6.28 checkpatch script
(trailing statements should be on the next line / struct should normally be
const).
The patch below has been tested as follows:
- Reran scripts/run-regression-tests -k 2.6.24.7 -k 2.6.25.20 -k 2.6.26.8 -k 2.6.27.21 -k 2.6.28.9 -k 2.6.29 and verified the output.
- Rebuilt, installed and loaded scst, iscsi-scst and srpt as follows:
make -s clean && make -s -C scst install && make -s -C iscsi-scst install && make -s -C srpt install && cd scstadmin && make -s && make -s install && modprobe scst_vdisk && modprobe iscsi-scst && dmesg

Signed-off-by: Bart Van Assche <bart.vanassche@gmail.com>

with minor cleanups and corrections in put_page_callback-2.6.29.patch



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@717 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2009-03-25 12:55:27 +00:00

630 lines
16 KiB
C

/*
* Copyright (C) 2002 - 2003 Ardis Technolgies <roman@ardistech.com>
* Copyright (C) 2007 - 2008 Vladislav Bolkhovitin
* Copyright (C) 2007 - 2008 CMS Distribution Limited
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __ISCSI_H__
#define __ISCSI_H__
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
#include <linux/net.h>
#include <net/sock.h>
#include <scst.h>
#include "iscsi_hdr.h"
#include "iscsi_scst.h"
#include "iscsi_dbg.h"
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x5
struct iscsi_sess_param {
int initial_r2t;
int immediate_data;
int max_connections;
unsigned int max_recv_data_length;
unsigned int max_xmit_data_length;
unsigned int max_burst_length;
unsigned int first_burst_length;
int default_wait_time;
int default_retain_time;
unsigned int max_outstanding_r2t;
int data_pdu_inorder;
int data_sequence_inorder;
int error_recovery_level;
int header_digest;
int data_digest;
int ofmarker;
int ifmarker;
int ofmarkint;
int ifmarkint;
};
struct iscsi_trgt_param {
int queued_cmnds;
};
struct network_thread_info {
struct task_struct *task;
unsigned int ready;
};
struct iscsi_cmnd;
struct iscsi_target {
struct scst_tgt *scst_tgt;
struct mutex target_mutex;
struct list_head session_list; /* protected by target_mutex */
/* Both protected by target_mutex */
struct iscsi_trgt_param trgt_param;
/*
* Put here to have uniform parameters checking and assigning
* from various places, including iscsi-scst-adm.
*/
struct iscsi_sess_param trgt_sess_param;
struct list_head target_list_entry;
u32 tid;
char name[ISCSI_NAME_LEN];
};
#define ISCSI_HASH_ORDER 8
#define cmnd_hashfn(itt) hash_long((itt), ISCSI_HASH_ORDER)
struct iscsi_session {
struct iscsi_target *target;
struct scst_session *scst_sess;
struct list_head pending_list; /* protected by sn_lock */
/* Unprotected, since accessed only from a single read thread */
u32 next_ttt;
u32 max_queued_cmnds; /* unprotected, since read-only */
atomic_t active_cmds;
spinlock_t sn_lock;
u32 exp_cmd_sn; /* protected by sn_lock */
/* All 3 protected by sn_lock */
int tm_active;
u32 tm_sn;
struct iscsi_cmnd *tm_rsp;
/* Read only, if there are connection(s) */
struct iscsi_sess_param sess_param;
spinlock_t cmnd_hash_lock;
struct list_head cmnd_hash[1 << ISCSI_HASH_ORDER];
struct list_head conn_list; /* protected by target_mutex */
struct list_head session_list_entry;
/* All protected by target_mutex, where necessary */
struct iscsi_session *sess_reinst_successor;
unsigned int sess_reinstating:1;
unsigned int sess_shutting_down:1;
/* All don't need any protection */
char *initiator_name;
u64 sid;
};
#define ISCSI_CONN_IOV_MAX (PAGE_SIZE/sizeof(struct iovec))
#define ISCSI_CONN_RD_STATE_IDLE 0
#define ISCSI_CONN_RD_STATE_IN_LIST 1
#define ISCSI_CONN_RD_STATE_PROCESSING 2
#define ISCSI_CONN_WR_STATE_IDLE 0
#define ISCSI_CONN_WR_STATE_IN_LIST 1
#define ISCSI_CONN_WR_STATE_SPACE_WAIT 2
#define ISCSI_CONN_WR_STATE_PROCESSING 3
struct iscsi_conn {
struct iscsi_session *session; /* owning session */
/* Both protected by session->sn_lock */
u32 stat_sn;
u32 exp_stat_sn;
spinlock_t cmd_list_lock; /* BH lock */
/* Protected by cmd_list_lock */
struct list_head cmd_list; /* in/outcoming pdus */
atomic_t conn_ref_cnt;
spinlock_t write_list_lock;
/* List of data pdus to be sent, protected by write_list_lock */
struct list_head write_list;
/* List of data pdus being sent, protected by write_list_lock */
struct list_head written_list;
struct timer_list rsp_timer;
/* All 2 protected by iscsi_wr_lock */
unsigned short wr_state;
unsigned short wr_space_ready:1;
struct list_head wr_list_entry;
#ifdef CONFIG_SCST_EXTRACHECKS
struct task_struct *wr_task;
#endif
/*
* All are unprotected, since accessed only from a single write
* thread.
*/
struct iscsi_cmnd *write_cmnd;
struct iovec *write_iop;
int write_iop_used;
struct iovec write_iov[2];
u32 write_size;
u32 write_offset;
int write_state;
/* Both don't need any protection */
struct file *file;
struct socket *sock;
void (*old_state_change)(struct sock *);
void (*old_data_ready)(struct sock *, int);
void (*old_write_space)(struct sock *);
/* Both read only */
int hdigest_type;
int ddigest_type;
/* All 5 protected by iscsi_rd_lock */
unsigned short rd_state;
unsigned short rd_data_ready:1;
/* Let's save some cache footprint by putting them here */
unsigned short closing:1;
unsigned short active_close:1;
unsigned short deleting:1;
struct list_head rd_list_entry;
#ifdef CONFIG_SCST_EXTRACHECKS
struct task_struct *rd_task;
#endif
/*
* All are unprotected, since accessed only from a single read
* thread.
*/
struct iscsi_cmnd *read_cmnd;
struct msghdr read_msg;
u32 read_size;
int read_state;
struct iovec *read_iov;
uint32_t rpadding;
struct iscsi_target *target;
struct list_head conn_list_entry; /* list entry in session conn_list */
/* All protected by target_mutex, where necessary */
struct iscsi_conn *conn_reinst_successor;
unsigned int conn_reinstating:1;
unsigned int conn_shutting_down:1;
struct completion ready_to_free;
/* Doesn't need any protection */
u16 cid;
};
struct iscsi_pdu {
struct iscsi_hdr bhs;
void *ahs;
unsigned int ahssize;
unsigned int datasize;
};
typedef void (iscsi_show_info_t)(struct seq_file *seq,
struct iscsi_target *target);
/** Command's states **/
/* New command and SCST processes it */
#define ISCSI_CMD_STATE_NEW 0
/* SCST processes cmd after scst_rx_cmd() */
#define ISCSI_CMD_STATE_RX_CMD 1
/* The command returned from preprocessing_done() */
#define ISCSI_CMD_STATE_AFTER_PREPROC 2
/* scst_restart_cmd() called and SCST processing it */
#define ISCSI_CMD_STATE_RESTARTED 3
/* SCST done processing */
#define ISCSI_CMD_STATE_PROCESSED 4
/* AEN processing */
#define ISCSI_CMD_STATE_AEN 5
/** Command's reject reasons **/
#define ISCSI_REJECT_SCSI_CMD 1
#define ISCSI_REJECT_CMD 2
#define ISCSI_REJECT_DATA 3
/*
* Most of the fields don't need any protection, since accessed from only a
* single thread, except where noted.
*/
struct iscsi_cmnd {
struct iscsi_conn *conn;
/*
* Some flags protected by conn->write_list_lock, but all modified only
* from single read thread or when there are no references to cmd.
*/
unsigned int hashed:1;
unsigned int should_close_conn:1;
unsigned int should_close_all_conn:1;
unsigned int pending:1;
unsigned int own_sg:1;
unsigned int on_write_list:1;
unsigned int write_processing_started:1;
unsigned int data_waiting:1;
unsigned int force_cleanup_done:1;
unsigned int dec_active_cmnds:1;
unsigned int ddigest_checked:1;
unsigned int rejected:1;
unsigned int reject_reason:2;
#ifdef CONFIG_SCST_EXTRACHECKS
unsigned int on_rx_digest_list:1;
unsigned int release_called:1;
#endif
/* It's async. with the above flags */
volatile unsigned int tm_aborted;
struct list_head hash_list_entry;
spinlock_t rsp_cmd_lock; /* BH lock */
/*
* Unions are for readability and grepability and to save some
* cache footprint.
*/
union {
/* Protected by rsp_cmd_lock */
struct list_head rsp_cmd_list;
struct list_head rsp_cmd_list_entry;
};
union {
struct list_head pending_list_entry;
struct list_head write_list_entry;
};
/* Both modified only from single write thread */
unsigned int on_written_list:1;
unsigned long write_timeout;
/*
* All unprotected, since could be accessed from only a single
* thread at time
*/
struct iscsi_cmnd *parent_req;
struct iscsi_cmnd *cmd_req;
/*
* All unprotected, since could be accessed from only a single
* thread at time
*/
union {
/* Request only fields */
struct {
struct list_head rx_ddigest_cmd_list;
struct list_head rx_ddigest_cmd_list_entry;
wait_queue_head_t scst_waitQ;
int scst_state;
union {
struct scst_cmd *scst_cmd;
struct scst_aen *scst_aen;
};
};
/* Response only fields */
struct {
struct scatterlist rsp_sg[2];
struct iscsi_sense_data sense_hdr;
};
};
atomic_t ref_cnt;
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
atomic_t net_ref_cnt;
#endif
struct iscsi_pdu pdu;
struct scatterlist *sg;
int sg_cnt;
unsigned int bufflen;
u32 r2t_sn;
u32 r2t_length;
u32 is_unsolicited_data;
u32 target_task_tag;
u32 outstanding_r2t;
u32 hdigest;
u32 ddigest;
struct list_head cmd_list_entry;
};
/* Flags for req_cmnd_release_force() */
#define ISCSI_FORCE_RELEASE_WRITE 1
#define ISCSI_RSP_TIMEOUT (30 * HZ)
extern struct mutex target_mgmt_mutex;
extern const struct file_operations ctr_fops;
extern spinlock_t iscsi_rd_lock;
extern struct list_head iscsi_rd_list;
extern wait_queue_head_t iscsi_rd_waitQ;
extern spinlock_t iscsi_wr_lock;
extern struct list_head iscsi_wr_list;
extern wait_queue_head_t iscsi_wr_waitQ;
/* iscsi.c */
extern struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *,
struct iscsi_cmnd *parent);
extern int cmnd_rx_start(struct iscsi_cmnd *);
extern void cmnd_rx_end(struct iscsi_cmnd *);
extern void cmnd_tx_start(struct iscsi_cmnd *);
extern void cmnd_tx_end(struct iscsi_cmnd *);
extern void req_cmnd_release_force(struct iscsi_cmnd *req, int flags);
extern void rsp_cmnd_release(struct iscsi_cmnd *);
extern void cmnd_done(struct iscsi_cmnd *cmnd);
extern void conn_abort(struct iscsi_conn *conn);
/* conn.c */
extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
extern void __iscsi_socket_bind(struct iscsi_conn *);
extern int conn_add(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int conn_free(struct iscsi_conn *);
#define ISCSI_CONN_ACTIVE_CLOSE 1
#define ISCSI_CONN_DELETING 2
extern void __mark_conn_closed(struct iscsi_conn *, int);
extern void mark_conn_closed(struct iscsi_conn *);
extern void iscsi_make_conn_wr_active(struct iscsi_conn *);
extern void conn_info_show(struct seq_file *, struct iscsi_session *);
/* nthread.c */
extern int iscsi_send(struct iscsi_conn *conn);
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
extern void iscsi_get_page_callback(struct page *page);
extern void iscsi_put_page_callback(struct page *page);
#endif
extern int istrd(void *arg);
extern int istwr(void *arg);
extern void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd);
/* target.c */
struct iscsi_target *target_lookup_by_id(u32);
extern int target_add(struct iscsi_kern_target_info *);
extern int target_del(u32 id);
extern void target_del_session(struct iscsi_target *target,
struct iscsi_session *session, int flags);
extern void target_del_all_sess(struct iscsi_target *target, int flags);
extern void target_del_all(void);
extern const struct seq_operations iscsi_seq_op;
/* config.c */
extern int iscsi_procfs_init(void);
extern void iscsi_procfs_exit(void);
/* session.c */
extern const struct file_operations session_seq_fops;
extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
extern void sess_enable_reinstated_sess(struct iscsi_session *);
extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
extern int session_del(struct iscsi_target *, u64);
extern int session_free(struct iscsi_session *session);
/* params.c */
extern int iscsi_param_set(struct iscsi_target *,
struct iscsi_kern_param_info *, int);
/* event.c */
extern int event_send(u32, u64, u32, u32, int);
extern int event_init(void);
extern void event_exit(void);
#define get_pgcnt(size, offset) \
((((size) + ((offset) & ~PAGE_MASK)) + PAGE_SIZE - 1) >> PAGE_SHIFT)
static inline void iscsi_cmnd_get_length(struct iscsi_pdu *pdu)
{
#if defined(__BIG_ENDIAN)
pdu->ahssize = pdu->bhs.length.ahslength * 4;
pdu->datasize = pdu->bhs.length.datalength;
#elif defined(__LITTLE_ENDIAN)
pdu->ahssize = (pdu->bhs.length & 0xff) * 4;
pdu->datasize = be32_to_cpu(pdu->bhs.length & ~0xff);
#else
#error
#endif
}
static inline void iscsi_cmnd_set_length(struct iscsi_pdu *pdu)
{
#if defined(__BIG_ENDIAN)
pdu->bhs.length.ahslength = pdu->ahssize / 4;
pdu->bhs.length.datalength = pdu->datasize;
#elif defined(__LITTLE_ENDIAN)
pdu->bhs.length = cpu_to_be32(pdu->datasize) | (pdu->ahssize / 4);
#else
#error
#endif
}
extern struct scst_tgt_template iscsi_template;
/*
* Skip this command if result is not 0. Must be called under
* corresponding lock.
*/
static inline bool cmnd_get_check(struct iscsi_cmnd *cmnd)
{
int r = atomic_inc_return(&cmnd->ref_cnt);
int res;
if (unlikely(r == 1)) {
TRACE_DBG("cmnd %p is being destroyed", cmnd);
atomic_dec(&cmnd->ref_cnt);
res = 1;
/* Necessary code is serialized by locks in cmnd_done() */
} else {
TRACE_DBG("cmnd %p, new ref_cnt %d", cmnd,
atomic_read(&cmnd->ref_cnt));
res = 0;
}
return res;
}
static inline void cmnd_get(struct iscsi_cmnd *cmnd)
{
atomic_inc(&cmnd->ref_cnt);
TRACE_DBG("cmnd %p, new cmnd->ref_cnt %d", cmnd,
atomic_read(&cmnd->ref_cnt));
}
static inline void cmnd_get_ordered(struct iscsi_cmnd *cmnd)
{
cmnd_get(cmnd);
/* See comments for each cmnd_get_ordered() use */
smp_mb__after_atomic_inc();
}
static inline void cmnd_put(struct iscsi_cmnd *cmnd)
{
TRACE_DBG("cmnd %p, new ref_cnt %d", cmnd,
atomic_read(&cmnd->ref_cnt)-1);
EXTRACHECKS_BUG_ON(atomic_read(&cmnd->ref_cnt) == 0);
if (atomic_dec_and_test(&cmnd->ref_cnt))
cmnd_done(cmnd);
}
/* conn->write_list_lock supposed to be locked and BHs off */
static inline void cmd_add_on_write_list(struct iscsi_conn *conn,
struct iscsi_cmnd *cmnd)
{
TRACE_DBG("%p", cmnd);
list_add_tail(&cmnd->write_list_entry, &conn->write_list);
cmnd->on_write_list = 1;
}
/* conn->write_list_lock supposed to be locked and BHs off */
static inline void cmd_del_from_write_list(struct iscsi_cmnd *cmnd)
{
TRACE_DBG("%p", cmnd);
list_del(&cmnd->write_list_entry);
cmnd->on_write_list = 0;
}
static inline void cmd_add_on_rx_ddigest_list(struct iscsi_cmnd *req,
struct iscsi_cmnd *cmnd)
{
TRACE_DBG("Adding RX ddigest cmd %p to digest list "
"of req %p", cmnd, req);
list_add_tail(&cmnd->rx_ddigest_cmd_list_entry,
&req->rx_ddigest_cmd_list);
#ifdef CONFIG_SCST_EXTRACHECKS
cmnd->on_rx_digest_list = 1;
#endif
}
static inline void cmd_del_from_rx_ddigest_list(struct iscsi_cmnd *cmnd)
{
TRACE_DBG("Deleting RX digest cmd %p from digest list", cmnd);
list_del(&cmnd->rx_ddigest_cmd_list_entry);
#ifdef CONFIG_SCST_EXTRACHECKS
cmnd->on_rx_digest_list = 0;
#endif
}
static inline int test_write_ready(struct iscsi_conn *conn)
{
/*
* No need for write_list protection, in the worst case we will be
* restarted again.
*/
return !list_empty(&conn->write_list) || conn->write_cmnd;
}
static inline void conn_get(struct iscsi_conn *conn)
{
atomic_inc(&conn->conn_ref_cnt);
TRACE_DBG("conn %p, new conn_ref_cnt %d", conn,
atomic_read(&conn->conn_ref_cnt));
}
static inline void conn_get_ordered(struct iscsi_conn *conn)
{
conn_get(conn);
/* See comments for each conn_get_ordered() use */
smp_mb__after_atomic_inc();
}
static inline void conn_put(struct iscsi_conn *conn)
{
TRACE_DBG("conn %p, new conn_ref_cnt %d", conn,
atomic_read(&conn->conn_ref_cnt)-1);
sBUG_ON(atomic_read(&conn->conn_ref_cnt) == 0);
/*
* Make it always ordered to protect from undesired side effects like
* accessing just destroyed by close_conn() conn caused by reordering
* of this atomic_dec().
*/
smp_mb__before_atomic_dec();
atomic_dec(&conn->conn_ref_cnt);
}
#ifdef CONFIG_SCST_EXTRACHECKS
extern void iscsi_extracheck_is_rd_thread(struct iscsi_conn *conn);
extern void iscsi_extracheck_is_wr_thread(struct iscsi_conn *conn);
#else
static inline void iscsi_extracheck_is_rd_thread(struct iscsi_conn *conn) {}
static inline void iscsi_extracheck_is_wr_thread(struct iscsi_conn *conn) {}
#endif
#endif /* __ISCSI_H__ */