[SCSI] iscsi class: user device_for_each_child instead of duplicating session list
Currently we duplicate the list of sessions, because we were using the test for if a session was on the host list to indicate if the session was bound or unbound. We can instead use the target_id and fix up the class so that drivers like bnx2i do not have to manage the target id space. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
2261ec3d68
commit
7970634b81
6 changed files with 106 additions and 39 deletions
|
@ -437,7 +437,7 @@ iscsi_iser_session_create(struct Scsi_Host *shost,
|
||||||
cls_session = iscsi_session_setup(&iscsi_iser_transport, shost,
|
cls_session = iscsi_session_setup(&iscsi_iser_transport, shost,
|
||||||
ISCSI_DEF_XMIT_CMDS_MAX,
|
ISCSI_DEF_XMIT_CMDS_MAX,
|
||||||
sizeof(struct iscsi_iser_task),
|
sizeof(struct iscsi_iser_task),
|
||||||
initial_cmdsn);
|
initial_cmdsn, 0);
|
||||||
if (!cls_session)
|
if (!cls_session)
|
||||||
goto remove_host;
|
goto remove_host;
|
||||||
session = cls_session->dd_data;
|
session = cls_session->dd_data;
|
||||||
|
|
|
@ -1868,7 +1868,7 @@ iscsi_tcp_session_create(struct Scsi_Host *shost, uint16_t cmds_max,
|
||||||
|
|
||||||
cls_session = iscsi_session_setup(&iscsi_tcp_transport, shost, cmds_max,
|
cls_session = iscsi_session_setup(&iscsi_tcp_transport, shost, cmds_max,
|
||||||
sizeof(struct iscsi_tcp_task),
|
sizeof(struct iscsi_tcp_task),
|
||||||
initial_cmdsn);
|
initial_cmdsn, 0);
|
||||||
if (!cls_session)
|
if (!cls_session)
|
||||||
goto remove_host;
|
goto remove_host;
|
||||||
session = cls_session->dd_data;
|
session = cls_session->dd_data;
|
||||||
|
|
|
@ -1897,7 +1897,7 @@ EXPORT_SYMBOL_GPL(iscsi_host_free);
|
||||||
struct iscsi_cls_session *
|
struct iscsi_cls_session *
|
||||||
iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
|
iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
|
||||||
uint16_t scsi_cmds_max, int cmd_task_size,
|
uint16_t scsi_cmds_max, int cmd_task_size,
|
||||||
uint32_t initial_cmdsn)
|
uint32_t initial_cmdsn, unsigned int id)
|
||||||
{
|
{
|
||||||
struct iscsi_session *session;
|
struct iscsi_session *session;
|
||||||
struct iscsi_cls_session *cls_session;
|
struct iscsi_cls_session *cls_session;
|
||||||
|
@ -1957,7 +1957,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
|
||||||
if (!try_module_get(iscsit->owner))
|
if (!try_module_get(iscsit->owner))
|
||||||
goto module_get_fail;
|
goto module_get_fail;
|
||||||
|
|
||||||
if (iscsi_add_session(cls_session, 0))
|
if (iscsi_add_session(cls_session, id))
|
||||||
goto cls_session_fail;
|
goto cls_session_fail;
|
||||||
return cls_session;
|
return cls_session;
|
||||||
|
|
||||||
|
|
|
@ -119,9 +119,8 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
|
||||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
struct iscsi_cls_host *ihost = shost->shost_data;
|
||||||
|
|
||||||
memset(ihost, 0, sizeof(*ihost));
|
memset(ihost, 0, sizeof(*ihost));
|
||||||
INIT_LIST_HEAD(&ihost->sessions);
|
|
||||||
mutex_init(&ihost->mutex);
|
|
||||||
atomic_set(&ihost->nr_scans, 0);
|
atomic_set(&ihost->nr_scans, 0);
|
||||||
|
mutex_init(&ihost->mutex);
|
||||||
|
|
||||||
snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d",
|
snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d",
|
||||||
shost->host_no);
|
shost->host_no);
|
||||||
|
@ -316,22 +315,61 @@ int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iscsi_scan_finished);
|
EXPORT_SYMBOL_GPL(iscsi_scan_finished);
|
||||||
|
|
||||||
|
struct iscsi_scan_data {
|
||||||
|
unsigned int channel;
|
||||||
|
unsigned int id;
|
||||||
|
unsigned int lun;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iscsi_user_scan_session(struct device *dev, void *data)
|
||||||
|
{
|
||||||
|
struct iscsi_scan_data *scan_data = data;
|
||||||
|
struct iscsi_cls_session *session;
|
||||||
|
struct Scsi_Host *shost;
|
||||||
|
struct iscsi_cls_host *ihost;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int id;
|
||||||
|
|
||||||
|
if (!iscsi_is_session_dev(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
session = iscsi_dev_to_session(dev);
|
||||||
|
shost = iscsi_session_to_shost(session);
|
||||||
|
ihost = shost->shost_data;
|
||||||
|
|
||||||
|
mutex_lock(&ihost->mutex);
|
||||||
|
spin_lock_irqsave(&session->lock, flags);
|
||||||
|
if (session->state != ISCSI_SESSION_LOGGED_IN) {
|
||||||
|
spin_unlock_irqrestore(&session->lock, flags);
|
||||||
|
mutex_unlock(&ihost->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
id = session->target_id;
|
||||||
|
spin_unlock_irqrestore(&session->lock, flags);
|
||||||
|
|
||||||
|
if (id != ISCSI_MAX_TARGET) {
|
||||||
|
if ((scan_data->channel == SCAN_WILD_CARD ||
|
||||||
|
scan_data->channel == 0) &&
|
||||||
|
(scan_data->id == SCAN_WILD_CARD ||
|
||||||
|
scan_data->id == id))
|
||||||
|
scsi_scan_target(&session->dev, 0, id,
|
||||||
|
scan_data->lun, 1);
|
||||||
|
}
|
||||||
|
mutex_unlock(&ihost->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
|
static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
|
||||||
uint id, uint lun)
|
uint id, uint lun)
|
||||||
{
|
{
|
||||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
struct iscsi_scan_data scan_data;
|
||||||
struct iscsi_cls_session *session;
|
|
||||||
|
|
||||||
mutex_lock(&ihost->mutex);
|
scan_data.channel = channel;
|
||||||
list_for_each_entry(session, &ihost->sessions, host_list) {
|
scan_data.id = id;
|
||||||
if ((channel == SCAN_WILD_CARD || channel == 0) &&
|
scan_data.lun = lun;
|
||||||
(id == SCAN_WILD_CARD || id == session->target_id))
|
|
||||||
scsi_scan_target(&session->dev, 0,
|
|
||||||
session->target_id, lun, 1);
|
|
||||||
}
|
|
||||||
mutex_unlock(&ihost->mutex);
|
|
||||||
|
|
||||||
return 0;
|
return device_for_each_child(&shost->shost_gendev, &scan_data,
|
||||||
|
iscsi_user_scan_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iscsi_scan_session(struct work_struct *work)
|
static void iscsi_scan_session(struct work_struct *work)
|
||||||
|
@ -340,18 +378,13 @@ static void iscsi_scan_session(struct work_struct *work)
|
||||||
container_of(work, struct iscsi_cls_session, scan_work);
|
container_of(work, struct iscsi_cls_session, scan_work);
|
||||||
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
||||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
struct iscsi_cls_host *ihost = shost->shost_data;
|
||||||
unsigned long flags;
|
struct iscsi_scan_data scan_data;
|
||||||
|
|
||||||
spin_lock_irqsave(&session->lock, flags);
|
scan_data.channel = 0;
|
||||||
if (session->state != ISCSI_SESSION_LOGGED_IN) {
|
scan_data.id = SCAN_WILD_CARD;
|
||||||
spin_unlock_irqrestore(&session->lock, flags);
|
scan_data.lun = SCAN_WILD_CARD;
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&session->lock, flags);
|
|
||||||
|
|
||||||
scsi_scan_target(&session->dev, 0, session->target_id,
|
iscsi_user_scan_session(&session->dev, &scan_data);
|
||||||
SCAN_WILD_CARD, 1);
|
|
||||||
done:
|
|
||||||
atomic_dec(&ihost->nr_scans);
|
atomic_dec(&ihost->nr_scans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,14 +493,18 @@ static void __iscsi_unbind_session(struct work_struct *work)
|
||||||
unbind_work);
|
unbind_work);
|
||||||
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
||||||
struct iscsi_cls_host *ihost = shost->shost_data;
|
struct iscsi_cls_host *ihost = shost->shost_data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* Prevent new scans and make sure scanning is not in progress */
|
/* Prevent new scans and make sure scanning is not in progress */
|
||||||
mutex_lock(&ihost->mutex);
|
mutex_lock(&ihost->mutex);
|
||||||
if (list_empty(&session->host_list)) {
|
spin_lock_irqsave(&session->lock, flags);
|
||||||
|
if (session->target_id == ISCSI_MAX_TARGET) {
|
||||||
|
spin_unlock_irqrestore(&session->lock, flags);
|
||||||
mutex_unlock(&ihost->mutex);
|
mutex_unlock(&ihost->mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
list_del_init(&session->host_list);
|
session->target_id = ISCSI_MAX_TARGET;
|
||||||
|
spin_unlock_irqrestore(&session->lock, flags);
|
||||||
mutex_unlock(&ihost->mutex);
|
mutex_unlock(&ihost->mutex);
|
||||||
|
|
||||||
scsi_remove_target(&session->dev);
|
scsi_remove_target(&session->dev);
|
||||||
|
@ -497,7 +534,6 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
|
||||||
session->recovery_tmo = 120;
|
session->recovery_tmo = 120;
|
||||||
session->state = ISCSI_SESSION_FREE;
|
session->state = ISCSI_SESSION_FREE;
|
||||||
INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
|
INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
|
||||||
INIT_LIST_HEAD(&session->host_list);
|
|
||||||
INIT_LIST_HEAD(&session->sess_list);
|
INIT_LIST_HEAD(&session->sess_list);
|
||||||
INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
|
INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
|
||||||
INIT_WORK(&session->block_work, __iscsi_block_session);
|
INIT_WORK(&session->block_work, __iscsi_block_session);
|
||||||
|
@ -516,16 +552,51 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iscsi_alloc_session);
|
EXPORT_SYMBOL_GPL(iscsi_alloc_session);
|
||||||
|
|
||||||
|
static int iscsi_get_next_target_id(struct device *dev, void *data)
|
||||||
|
{
|
||||||
|
struct iscsi_cls_session *session;
|
||||||
|
unsigned long flags;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!iscsi_is_session_dev(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
session = iscsi_dev_to_session(dev);
|
||||||
|
spin_lock_irqsave(&session->lock, flags);
|
||||||
|
if (*((unsigned int *) data) == session->target_id)
|
||||||
|
err = -EEXIST;
|
||||||
|
spin_unlock_irqrestore(&session->lock, flags);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
|
int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
|
||||||
{
|
{
|
||||||
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
struct Scsi_Host *shost = iscsi_session_to_shost(session);
|
||||||
struct iscsi_cls_host *ihost;
|
struct iscsi_cls_host *ihost;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
unsigned int id = target_id;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ihost = shost->shost_data;
|
ihost = shost->shost_data;
|
||||||
session->sid = atomic_add_return(1, &iscsi_session_nr);
|
session->sid = atomic_add_return(1, &iscsi_session_nr);
|
||||||
session->target_id = target_id;
|
|
||||||
|
if (id == ISCSI_MAX_TARGET) {
|
||||||
|
for (id = 0; id < ISCSI_MAX_TARGET; id++) {
|
||||||
|
err = device_for_each_child(&shost->shost_gendev, &id,
|
||||||
|
iscsi_get_next_target_id);
|
||||||
|
if (!err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == ISCSI_MAX_TARGET) {
|
||||||
|
iscsi_cls_session_printk(KERN_ERR, session,
|
||||||
|
"Too many iscsi targets. Max "
|
||||||
|
"number of targets is %d.\n",
|
||||||
|
ISCSI_MAX_TARGET - 1);
|
||||||
|
goto release_host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session->target_id = id;
|
||||||
|
|
||||||
snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
|
snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
|
||||||
session->sid);
|
session->sid);
|
||||||
|
@ -541,10 +612,6 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
|
||||||
list_add(&session->sess_list, &sesslist);
|
list_add(&session->sess_list, &sesslist);
|
||||||
spin_unlock_irqrestore(&sesslock, flags);
|
spin_unlock_irqrestore(&sesslock, flags);
|
||||||
|
|
||||||
mutex_lock(&ihost->mutex);
|
|
||||||
list_add(&session->host_list, &ihost->sessions);
|
|
||||||
mutex_unlock(&ihost->mutex);
|
|
||||||
|
|
||||||
iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
|
iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ extern void iscsi_host_free(struct Scsi_Host *shost);
|
||||||
*/
|
*/
|
||||||
extern struct iscsi_cls_session *
|
extern struct iscsi_cls_session *
|
||||||
iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
|
iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
|
||||||
uint16_t, int, uint32_t);
|
uint16_t, int, uint32_t, unsigned int);
|
||||||
extern void iscsi_session_teardown(struct iscsi_cls_session *);
|
extern void iscsi_session_teardown(struct iscsi_cls_session *);
|
||||||
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
|
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
|
||||||
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||||
|
|
|
@ -161,9 +161,10 @@ enum {
|
||||||
ISCSI_SESSION_FREE,
|
ISCSI_SESSION_FREE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ISCSI_MAX_TARGET -1
|
||||||
|
|
||||||
struct iscsi_cls_session {
|
struct iscsi_cls_session {
|
||||||
struct list_head sess_list; /* item in session_list */
|
struct list_head sess_list; /* item in session_list */
|
||||||
struct list_head host_list;
|
|
||||||
struct iscsi_transport *transport;
|
struct iscsi_transport *transport;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct work_struct block_work;
|
struct work_struct block_work;
|
||||||
|
@ -175,7 +176,7 @@ struct iscsi_cls_session {
|
||||||
int recovery_tmo;
|
int recovery_tmo;
|
||||||
struct delayed_work recovery_work;
|
struct delayed_work recovery_work;
|
||||||
|
|
||||||
int target_id;
|
unsigned int target_id;
|
||||||
|
|
||||||
int state;
|
int state;
|
||||||
int sid; /* session id */
|
int sid; /* session id */
|
||||||
|
@ -193,7 +194,6 @@ struct iscsi_cls_session {
|
||||||
iscsi_dev_to_session(_stgt->dev.parent)
|
iscsi_dev_to_session(_stgt->dev.parent)
|
||||||
|
|
||||||
struct iscsi_cls_host {
|
struct iscsi_cls_host {
|
||||||
struct list_head sessions;
|
|
||||||
atomic_t nr_scans;
|
atomic_t nr_scans;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
struct workqueue_struct *scan_workq;
|
struct workqueue_struct *scan_workq;
|
||||||
|
|
Loading…
Reference in a new issue