[SCSI] iscsi: seperate iscsi interface from setup functions
This is the second version of the patch to address Christoph's comments. Instead of doing the lib, I just kept everything in scsi_trnapsort_iscsi.c like the FC and SPI class. This was becuase the driver model and sysfs class is tied to the session and connection setup so separating did not buy very much at this time. The reason for this patch was becuase HW iscsi LLDs like qla4xxx cannot use the iscsi class becuase the scsi_host was tied to the interface and class code. This patch just seperates the session from scsi host so that LLDs that allocate the host per some resource like pci device can still use the class. This is also fixes a couple refcount bugs that can be triggered when users have a sysfs file open, close the session, then read or write to the file. Signed-off-by: Alex Aizman <itn780@yahoo.com> Signed-off-by: Dmitry Yusupov <dmitry_yus@yahoo.com> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
7cae5159dd
commit
7b8631b53b
4 changed files with 609 additions and 487 deletions
|
@ -2435,17 +2435,20 @@ iscsi_pool_free(struct iscsi_queue *q, void **items)
|
|||
kfree(items);
|
||||
}
|
||||
|
||||
static iscsi_connh_t
|
||||
iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx)
|
||||
static struct iscsi_cls_conn *
|
||||
iscsi_conn_create(struct Scsi_Host *shost, uint32_t conn_idx)
|
||||
{
|
||||
struct iscsi_session *session = iscsi_ptr(sessionh);
|
||||
struct iscsi_conn *conn = NULL;
|
||||
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
|
||||
struct iscsi_conn *conn;
|
||||
struct iscsi_cls_conn *cls_conn;
|
||||
|
||||
cls_conn = iscsi_create_conn(hostdata_session(shost->hostdata),
|
||||
conn_idx);
|
||||
if (!cls_conn)
|
||||
return NULL;
|
||||
conn = cls_conn->dd_data;
|
||||
|
||||
conn = kmalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
|
||||
if (conn == NULL)
|
||||
goto conn_alloc_fail;
|
||||
memset(conn, 0, sizeof(struct iscsi_conn));
|
||||
|
||||
conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
|
||||
conn->in_progress = IN_PROGRESS_WAIT_HEADER;
|
||||
conn->id = conn_idx;
|
||||
|
@ -2507,7 +2510,7 @@ iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx)
|
|||
mutex_init(&conn->xmitmutex);
|
||||
init_waitqueue_head(&conn->ehwait);
|
||||
|
||||
return iscsi_handle(conn);
|
||||
return cls_conn;
|
||||
|
||||
max_recv_dlenght_alloc_fail:
|
||||
spin_lock_bh(&session->lock);
|
||||
|
@ -2523,15 +2526,14 @@ immqueue_alloc_fail:
|
|||
writequeue_alloc_fail:
|
||||
kfifo_free(conn->xmitqueue);
|
||||
xmitqueue_alloc_fail:
|
||||
kfree(conn);
|
||||
conn_alloc_fail:
|
||||
return iscsi_handle(NULL);
|
||||
iscsi_destroy_conn(cls_conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_conn_destroy(iscsi_connh_t connh)
|
||||
iscsi_conn_destroy(struct iscsi_cls_conn *cls_conn)
|
||||
{
|
||||
struct iscsi_conn *conn = iscsi_ptr(connh);
|
||||
struct iscsi_conn *conn = cls_conn->dd_data;
|
||||
struct iscsi_session *session = conn->session;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -2626,7 +2628,8 @@ iscsi_conn_destroy(iscsi_connh_t connh)
|
|||
kfifo_free(conn->writequeue);
|
||||
kfifo_free(conn->immqueue);
|
||||
kfifo_free(conn->mgmtqueue);
|
||||
kfree(conn);
|
||||
|
||||
iscsi_destroy_conn(cls_conn);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -3257,17 +3260,23 @@ static struct scsi_host_template iscsi_sht = {
|
|||
.this_id = -1,
|
||||
};
|
||||
|
||||
static iscsi_sessionh_t
|
||||
iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host)
|
||||
static struct iscsi_transport iscsi_tcp_transport;
|
||||
|
||||
static struct Scsi_Host *
|
||||
iscsi_session_create(struct scsi_transport_template *scsit,
|
||||
uint32_t initial_cmdsn)
|
||||
{
|
||||
int cmd_i;
|
||||
struct Scsi_Host *shost;
|
||||
struct iscsi_session *session;
|
||||
int cmd_i;
|
||||
|
||||
session = iscsi_hostdata(host->hostdata);
|
||||
shost = iscsi_transport_create_session(scsit, &iscsi_tcp_transport);
|
||||
if (!shost)
|
||||
return NULL;
|
||||
|
||||
session = iscsi_hostdata(shost->hostdata);
|
||||
memset(session, 0, sizeof(struct iscsi_session));
|
||||
|
||||
session->host = host;
|
||||
session->id = host->host_no;
|
||||
session->host = shost;
|
||||
session->state = ISCSI_STATE_LOGGED_IN;
|
||||
session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
|
||||
session->cmds_max = ISCSI_XMIT_CMDS_MAX;
|
||||
|
@ -3311,7 +3320,7 @@ iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host)
|
|||
if (iscsi_r2tpool_alloc(session))
|
||||
goto r2tpool_alloc_fail;
|
||||
|
||||
return iscsi_handle(session);
|
||||
return shost;
|
||||
|
||||
r2tpool_alloc_fail:
|
||||
for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++)
|
||||
|
@ -3321,15 +3330,15 @@ immdata_alloc_fail:
|
|||
mgmtpool_alloc_fail:
|
||||
iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
|
||||
cmdpool_alloc_fail:
|
||||
return iscsi_handle(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_session_destroy(iscsi_sessionh_t sessionh)
|
||||
iscsi_session_destroy(struct Scsi_Host *shost)
|
||||
{
|
||||
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
|
||||
int cmd_i;
|
||||
struct iscsi_data_task *dtask, *n;
|
||||
struct iscsi_session *session = iscsi_ptr(sessionh);
|
||||
|
||||
for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
|
||||
struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
|
||||
|
@ -3345,6 +3354,8 @@ iscsi_session_destroy(iscsi_sessionh_t sessionh)
|
|||
iscsi_r2tpool_free(session);
|
||||
iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
|
||||
iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
|
||||
|
||||
iscsi_transport_destroy_session(shost);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -3493,25 +3504,12 @@ iscsi_conn_set_param(iscsi_connh_t connh, enum iscsi_param param,
|
|||
}
|
||||
|
||||
static int
|
||||
iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param,
|
||||
uint32_t *value)
|
||||
iscsi_session_get_param(struct Scsi_Host *shost,
|
||||
enum iscsi_param param, uint32_t *value)
|
||||
{
|
||||
struct iscsi_conn *conn = iscsi_ptr(connh);
|
||||
struct iscsi_session *session = conn->session;
|
||||
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
|
||||
|
||||
switch(param) {
|
||||
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
||||
*value = conn->max_recv_dlength;
|
||||
break;
|
||||
case ISCSI_PARAM_MAX_XMIT_DLENGTH:
|
||||
*value = conn->max_xmit_dlength;
|
||||
break;
|
||||
case ISCSI_PARAM_HDRDGST_EN:
|
||||
*value = conn->hdrdgst_en;
|
||||
break;
|
||||
case ISCSI_PARAM_DATADGST_EN:
|
||||
*value = conn->datadgst_en;
|
||||
break;
|
||||
case ISCSI_PARAM_INITIAL_R2T_EN:
|
||||
*value = session->initial_r2t_en;
|
||||
break;
|
||||
|
@ -3549,6 +3547,31 @@ iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
iscsi_conn_get_param(void *data, enum iscsi_param param, uint32_t *value)
|
||||
{
|
||||
struct iscsi_conn *conn = data;
|
||||
|
||||
switch(param) {
|
||||
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
||||
*value = conn->max_recv_dlength;
|
||||
break;
|
||||
case ISCSI_PARAM_MAX_XMIT_DLENGTH:
|
||||
*value = conn->max_xmit_dlength;
|
||||
break;
|
||||
case ISCSI_PARAM_HDRDGST_EN:
|
||||
*value = conn->hdrdgst_en;
|
||||
break;
|
||||
case ISCSI_PARAM_DATADGST_EN:
|
||||
*value = conn->datadgst_en;
|
||||
break;
|
||||
default:
|
||||
return ISCSI_ERR_PARAM_NOT_FOUND;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats)
|
||||
{
|
||||
|
@ -3593,6 +3616,7 @@ static struct iscsi_transport iscsi_tcp_transport = {
|
|||
| CAP_DATADGST,
|
||||
.host_template = &iscsi_sht,
|
||||
.hostdata_size = sizeof(struct iscsi_session),
|
||||
.conndata_size = sizeof(struct iscsi_conn),
|
||||
.max_conn = 1,
|
||||
.max_cmd_len = ISCSI_TCP_MAX_CMD_LEN,
|
||||
.create_session = iscsi_session_create,
|
||||
|
@ -3601,7 +3625,8 @@ static struct iscsi_transport iscsi_tcp_transport = {
|
|||
.bind_conn = iscsi_conn_bind,
|
||||
.destroy_conn = iscsi_conn_destroy,
|
||||
.set_param = iscsi_conn_set_param,
|
||||
.get_param = iscsi_conn_get_param,
|
||||
.get_conn_param = iscsi_conn_get_param,
|
||||
.get_session_param = iscsi_session_get_param,
|
||||
.start_conn = iscsi_conn_start,
|
||||
.stop_conn = iscsi_conn_stop,
|
||||
.send_pdu = iscsi_conn_send_pdu,
|
||||
|
@ -3611,8 +3636,6 @@ static struct iscsi_transport iscsi_tcp_transport = {
|
|||
static int __init
|
||||
iscsi_tcp_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (iscsi_max_lun < 1) {
|
||||
printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
|
||||
return -EINVAL;
|
||||
|
@ -3625,11 +3648,10 @@ iscsi_tcp_init(void)
|
|||
if (!taskcache)
|
||||
return -ENOMEM;
|
||||
|
||||
error = iscsi_register_transport(&iscsi_tcp_transport);
|
||||
if (error)
|
||||
if (!iscsi_register_transport(&iscsi_tcp_transport))
|
||||
kmem_cache_destroy(taskcache);
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -168,6 +168,12 @@ typedef uint64_t iscsi_connh_t; /* iSCSI Data-Path connection handle */
|
|||
|
||||
#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
|
||||
#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
|
||||
#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
|
||||
|
||||
/**
|
||||
* iscsi_hostdata - get LLD hostdata from scsi_host
|
||||
* @_hostdata: pointer to scsi host's hostdata
|
||||
**/
|
||||
#define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long))
|
||||
|
||||
/*
|
||||
|
|
|
@ -23,8 +23,14 @@
|
|||
#ifndef SCSI_TRANSPORT_ISCSI_H
|
||||
#define SCSI_TRANSPORT_ISCSI_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <scsi/iscsi_if.h>
|
||||
|
||||
struct scsi_transport_template;
|
||||
struct Scsi_Host;
|
||||
struct mempool_zone;
|
||||
struct iscsi_cls_conn;
|
||||
|
||||
/**
|
||||
* struct iscsi_transport - iSCSI Transport template
|
||||
*
|
||||
|
@ -48,23 +54,31 @@ struct iscsi_transport {
|
|||
char *name;
|
||||
unsigned int caps;
|
||||
struct scsi_host_template *host_template;
|
||||
/* LLD session/scsi_host data size */
|
||||
int hostdata_size;
|
||||
/* LLD iscsi_host data size */
|
||||
int ihostdata_size;
|
||||
/* LLD connection data size */
|
||||
int conndata_size;
|
||||
int max_lun;
|
||||
unsigned int max_conn;
|
||||
unsigned int max_cmd_len;
|
||||
iscsi_sessionh_t (*create_session) (uint32_t initial_cmdsn,
|
||||
struct Scsi_Host *shost);
|
||||
void (*destroy_session) (iscsi_sessionh_t session);
|
||||
iscsi_connh_t (*create_conn) (iscsi_sessionh_t session, uint32_t cid);
|
||||
struct Scsi_Host *(*create_session) (struct scsi_transport_template *t,
|
||||
uint32_t initial_cmdsn);
|
||||
void (*destroy_session) (struct Scsi_Host *shost);
|
||||
struct iscsi_cls_conn *(*create_conn) (struct Scsi_Host *shost,
|
||||
uint32_t cid);
|
||||
int (*bind_conn) (iscsi_sessionh_t session, iscsi_connh_t conn,
|
||||
uint32_t transport_fd, int is_leading);
|
||||
int (*start_conn) (iscsi_connh_t conn);
|
||||
void (*stop_conn) (iscsi_connh_t conn, int flag);
|
||||
void (*destroy_conn) (iscsi_connh_t conn);
|
||||
void (*destroy_conn) (struct iscsi_cls_conn *conn);
|
||||
int (*set_param) (iscsi_connh_t conn, enum iscsi_param param,
|
||||
uint32_t value);
|
||||
int (*get_param) (iscsi_connh_t conn, enum iscsi_param param,
|
||||
uint32_t *value);
|
||||
int (*get_conn_param) (void *conndata, enum iscsi_param param,
|
||||
uint32_t *value);
|
||||
int (*get_session_param) (struct Scsi_Host *shost,
|
||||
enum iscsi_param param, uint32_t *value);
|
||||
int (*send_pdu) (iscsi_connh_t conn, struct iscsi_hdr *hdr,
|
||||
char *data, uint32_t data_size);
|
||||
void (*get_stats) (iscsi_connh_t conn, struct iscsi_stats *stats);
|
||||
|
@ -73,7 +87,7 @@ struct iscsi_transport {
|
|||
/*
|
||||
* transport registration upcalls
|
||||
*/
|
||||
extern int iscsi_register_transport(struct iscsi_transport *tt);
|
||||
extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
|
||||
extern int iscsi_unregister_transport(struct iscsi_transport *tt);
|
||||
|
||||
/*
|
||||
|
@ -83,4 +97,49 @@ extern void iscsi_conn_error(iscsi_connh_t conn, enum iscsi_err error);
|
|||
extern int iscsi_recv_pdu(iscsi_connh_t conn, struct iscsi_hdr *hdr,
|
||||
char *data, uint32_t data_size);
|
||||
|
||||
struct iscsi_cls_conn {
|
||||
struct list_head conn_list; /* item in connlist */
|
||||
void *dd_data; /* LLD private data */
|
||||
struct iscsi_transport *transport;
|
||||
iscsi_connh_t connh;
|
||||
int active; /* must be accessed with the connlock */
|
||||
struct device dev; /* sysfs transport/container device */
|
||||
struct mempool_zone *z_error;
|
||||
struct mempool_zone *z_pdu;
|
||||
struct list_head freequeue;
|
||||
};
|
||||
|
||||
#define iscsi_dev_to_conn(_dev) \
|
||||
container_of(_dev, struct iscsi_cls_conn, dev)
|
||||
|
||||
struct iscsi_cls_session {
|
||||
struct list_head list; /* item in session_list */
|
||||
struct iscsi_transport *transport;
|
||||
struct device dev; /* sysfs transport/container device */
|
||||
};
|
||||
|
||||
#define iscsi_dev_to_session(_dev) \
|
||||
container_of(_dev, struct iscsi_cls_session, dev)
|
||||
|
||||
#define iscsi_session_to_shost(_session) \
|
||||
dev_to_shost(_session->dev.parent)
|
||||
|
||||
/*
|
||||
* session and connection functions that can be used by HW iSCSI LLDs
|
||||
*/
|
||||
extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
|
||||
struct iscsi_transport *t);
|
||||
extern int iscsi_destroy_session(struct iscsi_cls_session *session);
|
||||
extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
|
||||
uint32_t cid);
|
||||
extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
|
||||
|
||||
/*
|
||||
* session functions used by software iscsi
|
||||
*/
|
||||
extern struct Scsi_Host *
|
||||
iscsi_transport_create_session(struct scsi_transport_template *scsit,
|
||||
struct iscsi_transport *transport);
|
||||
extern int iscsi_transport_destroy_session(struct Scsi_Host *shost);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue