Minor cleanups and docs updates
[mirror/scst/.git] / iscsi-scst / kernel / target.c
1 /*
2  *  Copyright (C) 2002 - 2003 Ardis Technolgies <roman@ardistech.com>
3  *  Copyright (C) 2007 - 2008 Vladislav Bolkhovitin
4  *  Copyright (C) 2007 - 2008 CMS Distribution Limited
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 <linux/delay.h>
18
19 #include "iscsi.h"
20 #include "digest.h"
21
22 #define MAX_NR_TARGETS  (1UL << 30)
23
24 DEFINE_MUTEX(target_mgmt_mutex);
25
26 /* All 3 protected by target_mgmt_mutex */
27 static LIST_HEAD(target_list);
28 static u32 next_target_id;
29 static u32 nr_targets;
30
31 static struct iscsi_sess_param default_session_param = {
32         .initial_r2t = 1,
33         .immediate_data = 1,
34         .max_connections = 1,
35         .max_recv_data_length = 8192,
36         .max_xmit_data_length = 8192,
37         .max_burst_length = 262144,
38         .first_burst_length = 65536,
39         .default_wait_time = 2,
40         .default_retain_time = 20,
41         .max_outstanding_r2t = 1,
42         .data_pdu_inorder = 1,
43         .data_sequence_inorder = 1,
44         .error_recovery_level = 0,
45         .header_digest = DIGEST_NONE,
46         .data_digest = DIGEST_NONE,
47         .ofmarker = 0,
48         .ifmarker = 0,
49         .ofmarkint = 2048,
50         .ifmarkint = 2048,
51 };
52
53 static struct iscsi_trgt_param default_target_param = {
54         .queued_cmnds = DEFAULT_NR_QUEUED_CMNDS,
55 };
56
57 /* target_mgmt_mutex supposed to be locked */
58 struct iscsi_target *target_lookup_by_id(u32 id)
59 {
60         struct iscsi_target *target;
61
62         list_for_each_entry(target, &target_list, target_list_entry) {
63                 if (target->tid == id)
64                         return target;
65         }
66         return NULL;
67 }
68
69 /* target_mgmt_mutex supposed to be locked */
70 static struct iscsi_target *target_lookup_by_name(char *name)
71 {
72         struct iscsi_target *target;
73
74         list_for_each_entry(target, &target_list, target_list_entry) {
75                 if (!strcmp(target->name, name))
76                         return target;
77         }
78         return NULL;
79 }
80
81 /* target_mgmt_mutex supposed to be locked */
82 static int iscsi_target_create(struct target_info *info, u32 tid)
83 {
84         int err = -EINVAL, len;
85         char *name = info->name;
86         struct iscsi_target *target;
87
88         TRACE_MGMT_DBG("Creating target tid %u, name %s", tid, name);
89
90         len = strlen(name);
91         if (!len) {
92                 PRINT_ERROR("The length of the target name is zero %u", tid);
93                 goto out;
94         }
95
96         if (!try_module_get(THIS_MODULE)) {
97                 PRINT_ERROR("Fail to get module %u", tid);
98                 goto out;
99         }
100
101         target = kzalloc(sizeof(*target), GFP_KERNEL);
102         if (!target) {
103                 err = -ENOMEM;
104                 goto out_put;
105         }
106
107         target->tid = info->tid = tid;
108
109         memcpy(&target->trgt_sess_param, &default_session_param,
110                 sizeof(default_session_param));
111         memcpy(&target->trgt_param, &default_target_param,
112                 sizeof(default_target_param));
113
114         strncpy(target->name, name, sizeof(target->name) - 1);
115
116         mutex_init(&target->target_mutex);
117         INIT_LIST_HEAD(&target->session_list);
118
119         list_add(&target->target_list_entry, &target_list);
120
121         target->scst_tgt = scst_register(&iscsi_template, target->name);
122         if (!target->scst_tgt) {
123                 PRINT_ERROR("%s", "scst_register() failed");
124                 err = -EBUSY;
125                 goto out_free;
126         }
127
128         return 0;
129
130 out_free:
131         kfree(target);
132
133 out_put:
134         module_put(THIS_MODULE);
135
136 out:
137         return err;
138 }
139
140 /* target_mgmt_mutex supposed to be locked */
141 int target_add(struct target_info *info)
142 {
143         int err = -EEXIST;
144         u32 tid = info->tid;
145
146         if (nr_targets > MAX_NR_TARGETS) {
147                 err = -EBUSY;
148                 goto out;
149         }
150
151         if (target_lookup_by_name(info->name))
152                 goto out;
153
154         if (tid && target_lookup_by_id(tid))
155                 goto out;
156
157         if (!tid) {
158                 do {
159                         if (!++next_target_id)
160                                 ++next_target_id;
161                 } while (target_lookup_by_id(next_target_id));
162
163                 tid = next_target_id;
164         }
165
166         err = iscsi_target_create(info, tid);
167         if (!err)
168                 nr_targets++;
169 out:
170         return err;
171 }
172
173 static void target_destroy(struct iscsi_target *target)
174 {
175         TRACE_MGMT_DBG("Destroying target tid %u", target->tid);
176
177         scst_unregister(target->scst_tgt);
178
179         kfree(target);
180
181         module_put(THIS_MODULE);
182 }
183
184 /* target_mgmt_mutex supposed to be locked */
185 int target_del(u32 id)
186 {
187         struct iscsi_target *target;
188         int err;
189
190         target = target_lookup_by_id(id);
191         if (!target) {
192                 err = -ENOENT;
193                 goto out;
194         }
195
196         mutex_lock(&target->target_mutex);
197
198         if (!list_empty(&target->session_list)) {
199                 err = -EBUSY;
200                 goto out_unlock;
201         }
202
203         list_del(&target->target_list_entry);
204         nr_targets--;
205
206         mutex_unlock(&target->target_mutex);
207
208         target_destroy(target);
209         return 0;
210
211 out_unlock:
212         mutex_unlock(&target->target_mutex);
213
214 out:
215         return err;
216 }
217
218 void target_del_all(void)
219 {
220         struct iscsi_target *target, *t;
221
222         TRACE_ENTRY();
223
224         TRACE_MGMT_DBG("%s", "Deleting all targets");
225
226         /* Not the best, ToDo */
227         while (1) {
228                 mutex_lock(&target_mgmt_mutex);
229
230                 if (list_empty(&target_list))
231                         break;
232
233                 list_for_each_entry_safe(target, t, &target_list, target_list_entry) {
234                         struct iscsi_session *session, *ts;
235                         mutex_lock(&target->target_mutex);
236                         if (!list_empty(&target->session_list)) {
237                                 TRACE_MGMT_DBG("Cleaning up target %p", target);
238                                 list_for_each_entry_safe(session, ts, &target->session_list,
239                                                 session_list_entry) {
240                                         TRACE_MGMT_DBG("Cleaning up session %p", session);
241                                         if (!list_empty(&session->conn_list)) {
242                                                 struct iscsi_conn *conn, *tc;
243                                                 list_for_each_entry_safe(conn, tc,
244                                                                 &session->conn_list,
245                                                                 conn_list_entry) {
246                                                         TRACE_MGMT_DBG("Mark conn %p "
247                                                                 "closing", conn);
248                                                         __mark_conn_closed(conn,
249                                                                 ISCSI_CONN_ACTIVE_CLOSE|ISCSI_CONN_DELETING);
250                                                 }
251                                         } else {
252                                                 TRACE_MGMT_DBG("Freeing session %p "
253                                                         "without connections", session);
254                                                 session_del(target, session->sid);
255                                         }
256                                 }
257                                 mutex_unlock(&target->target_mutex);
258                         } else {
259                                 TRACE_MGMT_DBG("Deleting target %p", target);
260                                 list_del(&target->target_list_entry);
261                                 nr_targets--;
262                                 mutex_unlock(&target->target_mutex);
263                                 target_destroy(target);
264                                 continue;
265                         }
266                 }
267                 mutex_unlock(&target_mgmt_mutex);
268                 msleep(100);
269         }
270
271         mutex_unlock(&target_mgmt_mutex);
272
273         TRACE_MGMT_DBG("%s", "Deleting all targets finished");
274
275         TRACE_EXIT();
276         return;
277 }
278
279 int iscsi_info_show(struct seq_file *seq, iscsi_show_info_t *func)
280 {
281         int err;
282         struct iscsi_target *target;
283
284         err = mutex_lock_interruptible(&target_mgmt_mutex);
285         if (err < 0)
286                 return err;
287
288         list_for_each_entry(target, &target_list, target_list_entry) {
289                 seq_printf(seq, "tid:%u name:%s\n", target->tid, target->name);
290
291                 mutex_lock(&target->target_mutex);
292                 func(seq, target);
293                 mutex_unlock(&target->target_mutex);
294         }
295
296         mutex_unlock(&target_mgmt_mutex);
297
298         return 0;
299 }