Sysfs interface for targets made uniform. ISCSI-SCST made confirming the uniformity...
[mirror/scst/.git] / iscsi-scst / kernel / session.c
1 /*
2  *  Copyright (C) 2002 - 2003 Ardis Technolgies <roman@ardistech.com>
3  *  Copyright (C) 2007 - 2009 Vladislav Bolkhovitin
4  *  Copyright (C) 2007 - 2009 ID7 Ltd.
5  *
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
9  *  of the License.
10  *
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.
15  */
16
17 #include "iscsi.h"
18
19 /* target_mutex supposed to be locked */
20 struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
21 {
22         struct iscsi_session *session;
23
24         list_for_each_entry(session, &target->session_list,
25                         session_list_entry) {
26                 if (session->sid == sid)
27                         return session;
28         }
29         return NULL;
30 }
31
32 /* target_mgmt_mutex supposed to be locked */
33 static int iscsi_session_alloc(struct iscsi_target *target,
34         struct iscsi_kern_session_info *info, struct iscsi_session **result)
35 {
36         int err;
37         unsigned int i;
38         struct iscsi_session *session;
39         char *name = NULL;
40
41         session = kzalloc(sizeof(*session), GFP_KERNEL);
42         if (!session)
43                 return -ENOMEM;
44
45         session->target = target;
46         session->sid = info->sid;
47         atomic_set(&session->active_cmds, 0);
48         session->exp_cmd_sn = info->exp_cmd_sn;
49
50         session->initiator_name = kstrdup(info->initiator_name, GFP_KERNEL);
51         if (!session->initiator_name) {
52                 err = -ENOMEM;
53                 goto err;
54         }
55
56 #ifdef CONFIG_SCST_PROC
57         name = kmalloc(strlen(info->user_name) + strlen(info->initiator_name) +
58                         1, GFP_KERNEL);
59         if (name == NULL) {
60                 err = -ENOMEM;
61                 goto err;
62         }
63
64         if (info->user_name[0] != '\0')
65                 sprintf(name, "%s@%s", info->user_name, info->initiator_name);
66         else
67                 sprintf(name, "%s", info->initiator_name);
68 #else
69         name =  info->initiator_name;
70 #endif
71
72         INIT_LIST_HEAD(&session->conn_list);
73         INIT_LIST_HEAD(&session->pending_list);
74
75         spin_lock_init(&session->sn_lock);
76
77         spin_lock_init(&session->cmnd_data_wait_hash_lock);
78         for (i = 0; i < ARRAY_SIZE(session->cmnd_data_wait_hash); i++)
79                 INIT_LIST_HEAD(&session->cmnd_data_wait_hash[i]);
80
81         session->next_ttt = 1;
82
83         session->scst_sess = scst_register_session(target->scst_tgt, 0,
84                 name, NULL, NULL);
85         if (session->scst_sess == NULL) {
86                 PRINT_ERROR("%s", "scst_register_session() failed");
87                 err = -ENOMEM;
88                 goto err;
89         }
90
91 #ifdef CONFIG_SCST_PROC
92         kfree(name);
93 #endif
94
95         scst_sess_set_tgt_priv(session->scst_sess, session);
96
97         TRACE_MGMT_DBG("Session %p created: target %p, tid %u, sid %#Lx",
98                 session, target, target->tid, info->sid);
99
100         *result = session;
101         return 0;
102
103 err:
104         if (session) {
105                 kfree(session->initiator_name);
106                 kfree(session);
107 #ifdef CONFIG_SCST_PROC
108                 kfree(name);
109 #endif
110         }
111         return err;
112 }
113
114 /* target_mutex supposed to be locked */
115 void sess_reinst_finished(struct iscsi_session *sess)
116 {
117         struct iscsi_conn *c;
118
119         TRACE_ENTRY();
120
121         TRACE_MGMT_DBG("Enabling reinstate successor sess %p", sess);
122
123         sBUG_ON(!sess->sess_reinstating);
124
125         list_for_each_entry(c, &sess->conn_list, conn_list_entry) {
126                 conn_reinst_finished(c);
127         }
128         sess->sess_reinstating = 0;
129
130         TRACE_EXIT();
131         return;
132 }
133
134 /* target_mgmt_mutex supposed to be locked */
135 int __add_session(struct iscsi_target *target,
136         struct iscsi_kern_session_info *info)
137 {
138         struct iscsi_session *new_sess = NULL, *sess, *old_sess;
139         int err = 0, i;
140         union iscsi_sid sid;
141         bool reinstatement = false;
142         struct iscsi_kern_params_info *params_info;
143
144         TRACE_MGMT_DBG("Adding session SID %llx", info->sid);
145
146         err = iscsi_session_alloc(target, info, &new_sess);
147         if (err != 0)
148                 goto out;
149
150         mutex_lock(&target->target_mutex);
151
152         sess = session_lookup(target, info->sid);
153         if (sess != NULL) {
154                 PRINT_ERROR("Attempt to add session with existing SID %llx",
155                         info->sid);
156                 err = -EEXIST;
157                 goto out_err_unlock;
158         }
159
160         params_info = kmalloc(sizeof(*params_info), GFP_KERNEL);
161         if (params_info == NULL) {
162                 PRINT_ERROR("Unable to allocate params info (size %d)",
163                         sizeof(*params_info));
164                 err = -ENOMEM;
165                 goto out_err_unlock;
166         }
167
168         sid = *(union iscsi_sid *)&info->sid;
169         sid.id.tsih = 0;
170         old_sess = NULL;
171
172         /*
173          * We need to find the latest session to correctly handle
174          * multi-reinstatements
175          */
176         list_for_each_entry_reverse(sess, &target->session_list,
177                         session_list_entry) {
178                 union iscsi_sid i = *(union iscsi_sid *)&sess->sid;
179                 i.id.tsih = 0;
180                 if ((sid.id64 == i.id64) &&
181                     (strcmp(info->initiator_name, sess->initiator_name) == 0)) {
182                         if (!sess->sess_shutting_down) {
183                                 /* session reinstatement */
184                                 old_sess = sess;
185                         }
186                         break;
187                 }
188         }
189         sess = NULL;
190
191         list_add_tail(&new_sess->session_list_entry, &target->session_list);
192
193         memset(params_info, 0, sizeof(*params_info));
194         params_info->tid = target->tid;
195         params_info->sid = info->sid;
196         params_info->params_type = key_session;
197         for (i = 0; i < session_key_last; i++)
198                 params_info->session_params[i] = info->session_params[i];
199
200         err = iscsi_params_set(target, params_info, 1);
201         if (err != 0)
202                 goto out_del;
203
204         memset(params_info, 0, sizeof(*params_info));
205         params_info->tid = target->tid;
206         params_info->sid = info->sid;
207         params_info->params_type = key_target;
208         for (i = 0; i < target_key_last; i++)
209                 params_info->target_params[i] = info->target_params[i];
210
211         err = iscsi_params_set(target, params_info, 1);
212         if (err != 0)
213                 goto out_del;
214
215         kfree(params_info);
216         params_info = NULL;
217
218         if (old_sess != NULL) {
219                 reinstatement = true;
220
221                 TRACE_MGMT_DBG("Reinstating sess %p with SID %llx (old %p, "
222                         "SID %llx)", new_sess, new_sess->sid, old_sess,
223                         old_sess->sid);
224
225                 new_sess->sess_reinstating = 1;
226                 old_sess->sess_reinst_successor = new_sess;
227
228                 target_del_session(old_sess->target, old_sess, 0);
229         }
230
231         mutex_unlock(&target->target_mutex);
232
233         if (reinstatement) {
234                 /*
235                  * Mutex target_mgmt_mutex won't allow to add connections to
236                  * the new session after target_mutex was dropped, so it's safe
237                  * to replace the initial UA without it. We can't do it under
238                  * target_mutex, because otherwise we can establish a
239                  * circular locking dependency between target_mutex and
240                  * scst_mutex in SCST core (iscsi_report_aen() called by
241                  * SCST core under scst_mutex).
242                  */
243                 scst_set_initial_UA(new_sess->scst_sess,
244                         SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
245         }
246
247 out:
248         return err;
249
250 out_del:
251         list_del(&new_sess->session_list_entry);
252         kfree(params_info);
253
254 out_err_unlock:
255         mutex_unlock(&target->target_mutex);
256
257         scst_unregister_session(new_sess->scst_sess, 1, NULL);
258         new_sess->scst_sess = NULL;
259
260         mutex_lock(&target->target_mutex);
261         session_free(new_sess, false);
262         mutex_unlock(&target->target_mutex);
263         goto out;
264 }
265
266 static void __session_free(struct iscsi_session *session)
267 {
268         kfree(session->initiator_name);
269         kfree(session);
270 }
271
272 static void iscsi_unreg_sess_done(struct scst_session *scst_sess)
273 {
274         struct iscsi_session *session;
275
276         TRACE_ENTRY();
277
278         session = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
279
280         session->scst_sess = NULL;
281         __session_free(session);
282
283         TRACE_EXIT();
284         return;
285 }
286
287 /* target_mutex supposed to be locked */
288 int session_free(struct iscsi_session *session, bool del)
289 {
290         unsigned int i;
291
292         TRACE_MGMT_DBG("Freeing session %p (SID %llx)",
293                 session, session->sid);
294
295         sBUG_ON(!list_empty(&session->conn_list));
296         if (unlikely(atomic_read(&session->active_cmds) != 0)) {
297                 PRINT_CRIT_ERROR("active_cmds not 0 (%d)!!",
298                         atomic_read(&session->active_cmds));
299                 sBUG();
300         }
301
302         for (i = 0; i < ARRAY_SIZE(session->cmnd_data_wait_hash); i++)
303                 sBUG_ON(!list_empty(&session->cmnd_data_wait_hash[i]));
304
305         if (session->sess_reinst_successor != NULL)
306                 sess_reinst_finished(session->sess_reinst_successor);
307
308         if (session->sess_reinstating) {
309                 struct iscsi_session *s;
310                 TRACE_MGMT_DBG("Freeing being reinstated sess %p", session);
311                 list_for_each_entry(s, &session->target->session_list,
312                                                 session_list_entry) {
313                         if (s->sess_reinst_successor == session) {
314                                 s->sess_reinst_successor = NULL;
315                                 break;
316                         }
317                 }
318         }
319
320         if (del)
321                 list_del(&session->session_list_entry);
322
323         if (session->scst_sess != NULL) {
324                 /*
325                  * We must NOT call scst_unregister_session() in the waiting
326                  * mode, since we are under target_mutex. Otherwise we can
327                  * establish a circular locking dependency between target_mutex
328                  * and scst_mutex in SCST core (iscsi_report_aen() called by
329                  * SCST core under scst_mutex).
330                  */
331                 scst_unregister_session(session->scst_sess, 0,
332                         iscsi_unreg_sess_done);
333         } else
334                 __session_free(session);
335
336         return 0;
337 }
338
339 /* target_mutex supposed to be locked */
340 int __del_session(struct iscsi_target *target, u64 sid)
341 {
342         struct iscsi_session *session;
343
344         session = session_lookup(target, sid);
345         if (!session)
346                 return -ENOENT;
347
348         if (!list_empty(&session->conn_list)) {
349                 PRINT_ERROR("%llu still have connections",
350                             (long long unsigned int)session->sid);
351                 return -EBUSY;
352         }
353
354         return session_free(session, true);
355 }
356
357 #ifdef CONFIG_SCST_PROC
358
359 /* target_mutex supposed to be locked */
360 static void iscsi_session_info_show(struct seq_file *seq,
361                                     struct iscsi_target *target)
362 {
363         struct iscsi_session *session;
364
365         list_for_each_entry(session, &target->session_list,
366                             session_list_entry) {
367                 seq_printf(seq, "\tsid:%llx initiator:%s (reinstating %s)\n",
368                         (long long unsigned int)session->sid,
369                         session->initiator_name,
370                         session->sess_reinstating ? "yes" : "no");
371                 conn_info_show(seq, session);
372         }
373         return;
374 }
375
376 static int iscsi_session_seq_open(struct inode *inode, struct file *file)
377 {
378         int res;
379         res = seq_open(file, &iscsi_seq_op);
380         if (!res)
381                 ((struct seq_file *)file->private_data)->private =
382                         iscsi_session_info_show;
383         return res;
384 }
385
386 const struct file_operations session_seq_fops = {
387         .owner          = THIS_MODULE,
388         .open           = iscsi_session_seq_open,
389         .read           = seq_read,
390         .llseek         = seq_lseek,
391         .release        = seq_release,
392 };
393
394 #else /* CONFIG_SCST_PROC */
395
396 #define ISCSI_SESS_BOOL_PARAM_ATTR(name, exported_name)                         \
397 static ssize_t iscsi_sess_show_##name(struct kobject *kobj,                     \
398         struct kobj_attribute *attr, char *buf)                                 \
399 {                                                                               \
400         int pos;                                                                \
401         struct scst_session *scst_sess;                                         \
402         struct iscsi_session *sess;                                             \
403                                                                                 \
404         scst_sess = container_of(kobj, struct scst_session, sess_kobj);         \
405         sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);       \
406                                                                                 \
407         pos = sprintf(buf, "%s\n",                                              \
408                 iscsi_get_bool_value(sess->sess_params.name));                  \
409                                                                                 \
410         return pos;                                                             \
411 }                                                                               \
412                                                                                 \
413 static struct kobj_attribute iscsi_sess_attr_##name =                           \
414         __ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
415
416 #define ISCSI_SESS_INT_PARAM_ATTR(name, exported_name)                          \
417 static ssize_t iscsi_sess_show_##name(struct kobject *kobj,                     \
418         struct kobj_attribute *attr, char *buf)                                 \
419 {                                                                               \
420         int pos;                                                                \
421         struct scst_session *scst_sess;                                         \
422         struct iscsi_session *sess;                                             \
423                                                                                 \
424         scst_sess = container_of(kobj, struct scst_session, sess_kobj);         \
425         sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);       \
426                                                                                 \
427         pos = sprintf(buf, "%d\n", sess->sess_params.name);                     \
428                                                                                 \
429         return pos;                                                             \
430 }                                                                               \
431                                                                                 \
432 static struct kobj_attribute iscsi_sess_attr_##name =                           \
433         __ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
434
435 #define ISCSI_SESS_DIGEST_PARAM_ATTR(name, exported_name)                       \
436 static ssize_t iscsi_sess_show_##name(struct kobject *kobj,                     \
437         struct kobj_attribute *attr, char *buf)                                 \
438 {                                                                               \
439         int pos;                                                                \
440         struct scst_session *scst_sess;                                         \
441         struct iscsi_session *sess;                                             \
442         char digest_name[64];                                                   \
443                                                                                 \
444         scst_sess = container_of(kobj, struct scst_session, sess_kobj);         \
445         sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);       \
446                                                                                 \
447         pos = sprintf(buf, "%s\n", iscsi_get_digest_name(                       \
448                         sess->sess_params.name, digest_name));                  \
449                                                                                 \
450         return pos;                                                             \
451 }                                                                               \
452                                                                                 \
453 static struct kobj_attribute iscsi_sess_attr_##name =                           \
454         __ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
455
456 ISCSI_SESS_BOOL_PARAM_ATTR(initial_r2t, InitialR2T);
457 ISCSI_SESS_BOOL_PARAM_ATTR(immediate_data, ImmediateData);
458 ISCSI_SESS_INT_PARAM_ATTR(max_recv_data_length, MaxRecvDataSegmentLength);
459 ISCSI_SESS_INT_PARAM_ATTR(max_xmit_data_length, MaxXmitDataSegmentLength);
460 ISCSI_SESS_INT_PARAM_ATTR(max_burst_length, MaxBurstLength);
461 ISCSI_SESS_INT_PARAM_ATTR(first_burst_length, FirstBurstLength);
462 ISCSI_SESS_INT_PARAM_ATTR(max_outstanding_r2t, MaxOutstandingR2T);
463 ISCSI_SESS_DIGEST_PARAM_ATTR(header_digest, HeaderDigest);
464 ISCSI_SESS_DIGEST_PARAM_ATTR(data_digest, DataDigest);
465
466 static ssize_t iscsi_sess_sid_show(struct kobject *kobj,
467         struct kobj_attribute *attr, char *buf)
468 {
469         int pos;
470         struct scst_session *scst_sess;
471         struct iscsi_session *sess;
472
473         TRACE_ENTRY();
474
475         scst_sess = container_of(kobj, struct scst_session, sess_kobj);
476         sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
477
478         pos = sprintf(buf, "%llx\n", sess->sid);
479
480         TRACE_EXIT_RES(pos);
481         return pos;
482 }
483
484 static struct kobj_attribute iscsi_attr_sess_sid =
485         __ATTR(sid, S_IRUGO, iscsi_sess_sid_show, NULL);
486
487 static ssize_t iscsi_sess_reinstating_show(struct kobject *kobj,
488         struct kobj_attribute *attr, char *buf)
489 {
490         int pos;
491         struct scst_session *scst_sess;
492         struct iscsi_session *sess;
493
494         TRACE_ENTRY();
495
496         scst_sess = container_of(kobj, struct scst_session, sess_kobj);
497         sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
498
499         pos = sprintf(buf, "%d\n", sess->sess_reinstating ? 1 : 0);
500
501         TRACE_EXIT_RES(pos);
502         return pos;
503 }
504
505 static struct kobj_attribute iscsi_sess_attr_reinstating =
506         __ATTR(reinstating, S_IRUGO, iscsi_sess_reinstating_show, NULL);
507
508 static ssize_t iscsi_sess_force_close_store(struct kobject *kobj,
509         struct kobj_attribute *attr, const char *buf, size_t count)
510 {
511         int res;
512         struct scst_session *scst_sess;
513         struct iscsi_session *sess;
514         struct iscsi_conn *conn;
515
516         TRACE_ENTRY();
517
518         scst_sess = container_of(kobj, struct scst_session, sess_kobj);
519         sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
520
521         if (mutex_lock_interruptible(&sess->target->target_mutex) != 0) {
522                 res = -EINTR;
523                 goto out;
524         }
525
526         PRINT_INFO("Deleting session %llu with initiator %s (%p)",
527                 (long long unsigned int)sess->sid, sess->initiator_name, sess);
528
529         list_for_each_entry(conn, &sess->conn_list, conn_list_entry) {
530                 TRACE_MGMT_DBG("Deleting connection with initiator %p", conn);
531                 __mark_conn_closed(conn, ISCSI_CONN_ACTIVE_CLOSE|ISCSI_CONN_DELETING);
532         }
533
534         mutex_unlock(&sess->target->target_mutex);
535
536         res = count;
537
538 out:
539         TRACE_EXIT_RES(res);
540         return res;
541 }
542
543 static struct kobj_attribute iscsi_sess_attr_force_close =
544         __ATTR(force_close, S_IWUSR, NULL, iscsi_sess_force_close_store);
545
546 const struct attribute *iscsi_sess_attrs[] = {
547         &iscsi_sess_attr_initial_r2t.attr,
548         &iscsi_sess_attr_immediate_data.attr,
549         &iscsi_sess_attr_max_recv_data_length.attr,
550         &iscsi_sess_attr_max_xmit_data_length.attr,
551         &iscsi_sess_attr_max_burst_length.attr,
552         &iscsi_sess_attr_first_burst_length.attr,
553         &iscsi_sess_attr_max_outstanding_r2t.attr,
554         &iscsi_sess_attr_header_digest.attr,
555         &iscsi_sess_attr_data_digest.attr,
556         &iscsi_attr_sess_sid.attr,
557         &iscsi_sess_attr_reinstating.attr,
558         &iscsi_sess_attr_force_close.attr,
559         NULL,
560 };
561
562 #endif /* CONFIG_SCST_PROC */