2 * Copyright (C) 2002 - 2003 Ardis Technolgies <roman@ardistech.com>
3 * Copyright (C) 2007 - 2009 Vladislav Bolkhovitin
4 * Copyright (C) 2007 - 2009 ID7 Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, version 2
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
19 #ifdef CONFIG_SCST_PROC
20 int print_digest_state(char *p, size_t size, unsigned long flags)
22 static int print_digest_state(char *p, size_t size, unsigned long flags)
27 if (DIGEST_NONE & flags)
28 pos = scnprintf(p, size, "%s", "none");
29 else if (DIGEST_CRC32C & flags)
30 pos = scnprintf(p, size, "%s", "crc32c");
32 pos = scnprintf(p, size, "%s", "unknown");
37 /* target_mutex supposed to be locked */
38 struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
40 struct iscsi_session *session;
42 list_for_each_entry(session, &target->session_list,
44 if (session->sid == sid)
50 /* target_mgmt_mutex supposed to be locked */
51 static int iscsi_session_alloc(struct iscsi_target *target,
52 struct iscsi_kern_session_info *info, struct iscsi_session **result)
56 struct iscsi_session *session;
59 session = kzalloc(sizeof(*session), GFP_KERNEL);
63 session->target = target;
64 session->sid = info->sid;
65 session->sess_param = target->trgt_sess_param;
66 session->max_queued_cmnds = target->trgt_param.queued_cmnds;
67 atomic_set(&session->active_cmds, 0);
69 session->exp_cmd_sn = info->exp_cmd_sn;
71 session->initiator_name = kstrdup(info->initiator_name, GFP_KERNEL);
72 if (!session->initiator_name) {
77 name = kmalloc(strlen(info->user_name) + strlen(info->initiator_name) +
84 if (info->user_name[0] != '\0')
85 sprintf(name, "%s@%s", info->user_name, info->initiator_name);
87 sprintf(name, "%s", info->initiator_name);
89 INIT_LIST_HEAD(&session->conn_list);
90 INIT_LIST_HEAD(&session->pending_list);
92 spin_lock_init(&session->sn_lock);
94 spin_lock_init(&session->cmnd_hash_lock);
95 for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++)
96 INIT_LIST_HEAD(&session->cmnd_hash[i]);
98 session->next_ttt = 1;
100 session->scst_sess = scst_register_session(target->scst_tgt, 0,
102 if (session->scst_sess == NULL) {
103 PRINT_ERROR("%s", "scst_register_session() failed");
110 scst_sess_set_tgt_priv(session->scst_sess, session);
112 TRACE_MGMT_DBG("Session %p created: target %p, tid %u, sid %#Lx",
113 session, target, target->tid, info->sid);
120 kfree(session->initiator_name);
127 /* target_mutex supposed to be locked */
128 void sess_reinst_finished(struct iscsi_session *sess)
130 struct iscsi_conn *c;
134 TRACE_MGMT_DBG("Enabling reinstate successor sess %p", sess);
136 sBUG_ON(!sess->sess_reinstating);
138 list_for_each_entry(c, &sess->conn_list, conn_list_entry) {
139 conn_reinst_finished(c);
141 sess->sess_reinstating = 0;
147 /* target_mgmt_mutex supposed to be locked */
148 int session_add(struct iscsi_target *target,
149 struct iscsi_kern_session_info *info)
151 struct iscsi_session *new_sess = NULL, *sess, *old_sess;
154 bool reinstatement = false;
156 TRACE_MGMT_DBG("Adding session SID %llx", info->sid);
158 err = iscsi_session_alloc(target, info, &new_sess);
162 mutex_lock(&target->target_mutex);
164 sess = session_lookup(target, info->sid);
166 PRINT_ERROR("Attempt to add session with existing SID %llx",
172 sid = *(union iscsi_sid *)&info->sid;
177 * We need to find the latest session to correctly handle
178 * multi-reinstatements
180 list_for_each_entry_reverse(sess, &target->session_list,
181 session_list_entry) {
182 union iscsi_sid i = *(union iscsi_sid *)&sess->sid;
184 if ((sid.id64 == i.id64) &&
185 (strcmp(info->initiator_name, sess->initiator_name) == 0)) {
186 if (!sess->sess_shutting_down) {
187 /* session reinstatement */
195 list_add_tail(&new_sess->session_list_entry, &target->session_list);
197 if (old_sess != NULL) {
198 reinstatement = true;
200 TRACE_MGMT_DBG("Reinstating sess %p with SID %llx (old %p, "
201 "SID %llx)", new_sess, new_sess->sid, old_sess,
204 new_sess->sess_reinstating = 1;
205 old_sess->sess_reinst_successor = new_sess;
207 target_del_session(old_sess->target, old_sess, 0);
210 mutex_unlock(&target->target_mutex);
214 * Mutex target_mgmt_mutex won't allow to add connections to
215 * the new session after target_mutex was dropped, so it's safe
216 * to replace the initial UA without it. We can't do it under
217 * target_mutex, because otherwise we can establish a
218 * circular locking dependency between target_mutex and
219 * scst_mutex in SCST core (iscsi_report_aen() called by
220 * SCST core under scst_mutex).
222 scst_set_initial_UA(new_sess->scst_sess,
223 SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
230 mutex_unlock(&target->target_mutex);
232 scst_unregister_session(new_sess->scst_sess, 1, NULL);
233 new_sess->scst_sess = NULL;
235 mutex_lock(&target->target_mutex);
236 session_free(new_sess, false);
237 mutex_unlock(&target->target_mutex);
241 static void __session_free(struct iscsi_session *session)
243 kfree(session->initiator_name);
247 static void iscsi_unreg_sess_done(struct scst_session *scst_sess)
249 struct iscsi_session *session;
253 session = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
255 session->scst_sess = NULL;
256 __session_free(session);
262 /* target_mutex supposed to be locked */
263 int session_free(struct iscsi_session *session, bool del)
267 TRACE_MGMT_DBG("Freeing session %p (SID %llx)",
268 session, session->sid);
270 sBUG_ON(!list_empty(&session->conn_list));
271 if (unlikely(atomic_read(&session->active_cmds) != 0)) {
272 PRINT_CRIT_ERROR("active_cmds not 0 (%d)!!",
273 atomic_read(&session->active_cmds));
277 for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++)
278 sBUG_ON(!list_empty(&session->cmnd_hash[i]));
280 if (session->sess_reinst_successor != NULL)
281 sess_reinst_finished(session->sess_reinst_successor);
283 if (session->sess_reinstating) {
284 struct iscsi_session *s;
285 TRACE_MGMT_DBG("Freeing being reinstated sess %p", session);
286 list_for_each_entry(s, &session->target->session_list,
287 session_list_entry) {
288 if (s->sess_reinst_successor == session) {
289 s->sess_reinst_successor = NULL;
296 list_del(&session->session_list_entry);
298 if (session->scst_sess != NULL) {
300 * We must NOT call scst_unregister_session() in the waiting
301 * mode, since we are under target_mutex. Otherwise we can
302 * establish a circular locking dependency between target_mutex
303 * and scst_mutex in SCST core (iscsi_report_aen() called by
304 * SCST core under scst_mutex).
306 scst_unregister_session(session->scst_sess, 0,
307 iscsi_unreg_sess_done);
309 __session_free(session);
314 /* target_mutex supposed to be locked */
315 int session_del(struct iscsi_target *target, u64 sid)
317 struct iscsi_session *session;
319 session = session_lookup(target, sid);
323 if (!list_empty(&session->conn_list)) {
324 PRINT_ERROR("%llu still have connections",
325 (long long unsigned int)session->sid);
329 return session_free(session, true);
332 #ifdef CONFIG_SCST_PROC
334 /* target_mutex supposed to be locked */
335 static void iscsi_session_info_show(struct seq_file *seq,
336 struct iscsi_target *target)
338 struct iscsi_session *session;
340 list_for_each_entry(session, &target->session_list,
341 session_list_entry) {
342 seq_printf(seq, "\tsid:%llx initiator:%s (reinstating %s)\n",
343 (long long unsigned int)session->sid,
344 session->initiator_name,
345 session->sess_reinstating ? "yes" : "no");
346 conn_info_show(seq, session);
351 static int iscsi_session_seq_open(struct inode *inode, struct file *file)
354 res = seq_open(file, &iscsi_seq_op);
356 ((struct seq_file *)file->private_data)->private =
357 iscsi_session_info_show;
361 const struct file_operations session_seq_fops = {
362 .owner = THIS_MODULE,
363 .open = iscsi_session_seq_open,
366 .release = seq_release,
369 #else /* CONFIG_SCST_PROC */
371 static ssize_t iscsi_sess_sid_show(struct kobject *kobj,
372 struct kobj_attribute *attr, char *buf)
375 struct scst_session *scst_sess;
376 struct iscsi_session *sess;
380 scst_sess = container_of(kobj, struct scst_session, sess_kobj);
381 sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
383 pos = sprintf(buf, "%llx\n", sess->sid);
389 static struct kobj_attribute iscsi_sess_sid_attr =
390 __ATTR(sid, S_IRUGO, iscsi_sess_sid_show, NULL);
392 static ssize_t iscsi_sess_reinstating_show(struct kobject *kobj,
393 struct kobj_attribute *attr, char *buf)
396 struct scst_session *scst_sess;
397 struct iscsi_session *sess;
401 scst_sess = container_of(kobj, struct scst_session, sess_kobj);
402 sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
404 pos = sprintf(buf, "%d\n", sess->sess_reinstating ? 1 : 0);
410 static struct kobj_attribute iscsi_sess_reinstating_attr =
411 __ATTR(reinstating, S_IRUGO, iscsi_sess_reinstating_show, NULL);
413 static ssize_t iscsi_sess_hdigest_show(struct kobject *kobj,
414 struct kobj_attribute *attr, char *buf)
417 struct scst_session *scst_sess;
418 struct iscsi_session *sess;
422 scst_sess = container_of(kobj, struct scst_session, sess_kobj);
423 sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
425 pos = print_digest_state(buf, SCST_SYSFS_BLOCK_SIZE,
426 sess->sess_param.header_digest);
432 static struct kobj_attribute iscsi_sess_hdigest_attr =
433 __ATTR(hdigest, S_IRUGO, iscsi_sess_hdigest_show, NULL);
435 static ssize_t iscsi_sess_ddigest_show(struct kobject *kobj,
436 struct kobj_attribute *attr, char *buf)
439 struct scst_session *scst_sess;
440 struct iscsi_session *sess;
444 scst_sess = container_of(kobj, struct scst_session, sess_kobj);
445 sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
447 pos = print_digest_state(buf, SCST_SYSFS_BLOCK_SIZE,
448 sess->sess_param.data_digest);
454 static struct kobj_attribute iscsi_sess_ddigest_attr =
455 __ATTR(ddigest, S_IRUGO, iscsi_sess_ddigest_show, NULL);
457 const struct attribute *iscsi_sess_attrs[] = {
458 &iscsi_sess_sid_attr.attr,
459 &iscsi_sess_reinstating_attr.attr,
460 &iscsi_sess_hdigest_attr.attr,
461 &iscsi_sess_ddigest_attr.attr,
465 #endif /* CONFIG_SCST_PROC */