Commit d0f474e501929acdbd116cca39ef083012f70f25
Committed by
Nicholas Bellinger
1 parent
d5b4a21b3d
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
target: Use LIST_HEAD()/DEFINE_MUTEX() for static objects
Instead of static struct list_head foo; static struct mutex bar; ... INIT_LIST_HEAD(&foo); mutex_init(&bar); just do static LIST_HEAD(foo); static DEFINE_MUTEX(bar); Also remove some superfluous struct list_head and spinlock_t initialization calls where the variables are already defined using macros that initialize them. This saves a decent amount of compiled code too: add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-178 (-178) function old new delta target_core_init_configfs 898 850 -48 core_scsi3_emulate_pro_preempt 1742 1683 -59 iscsi_thread_set_init 159 88 -71 Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Showing 3 changed files with 4 additions and 14 deletions Inline Diff
drivers/target/iscsi/iscsi_target_tq.c
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the iSCSI Login Thread and Thread Queue functions. | 2 | * This file contains the iSCSI Login Thread and Thread Queue functions. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. |
5 | * | 5 | * |
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | 6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. |
7 | * | 7 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | ******************************************************************************/ | 19 | ******************************************************************************/ |
20 | 20 | ||
21 | #include <linux/kthread.h> | 21 | #include <linux/kthread.h> |
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | #include <linux/bitmap.h> | 23 | #include <linux/bitmap.h> |
24 | 24 | ||
25 | #include "iscsi_target_core.h" | 25 | #include "iscsi_target_core.h" |
26 | #include "iscsi_target_tq.h" | 26 | #include "iscsi_target_tq.h" |
27 | #include "iscsi_target.h" | 27 | #include "iscsi_target.h" |
28 | 28 | ||
29 | static LIST_HEAD(active_ts_list); | 29 | static LIST_HEAD(active_ts_list); |
30 | static LIST_HEAD(inactive_ts_list); | 30 | static LIST_HEAD(inactive_ts_list); |
31 | static DEFINE_SPINLOCK(active_ts_lock); | 31 | static DEFINE_SPINLOCK(active_ts_lock); |
32 | static DEFINE_SPINLOCK(inactive_ts_lock); | 32 | static DEFINE_SPINLOCK(inactive_ts_lock); |
33 | static DEFINE_SPINLOCK(ts_bitmap_lock); | 33 | static DEFINE_SPINLOCK(ts_bitmap_lock); |
34 | 34 | ||
35 | static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts) | 35 | static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts) |
36 | { | 36 | { |
37 | spin_lock(&active_ts_lock); | 37 | spin_lock(&active_ts_lock); |
38 | list_add_tail(&ts->ts_list, &active_ts_list); | 38 | list_add_tail(&ts->ts_list, &active_ts_list); |
39 | iscsit_global->active_ts++; | 39 | iscsit_global->active_ts++; |
40 | spin_unlock(&active_ts_lock); | 40 | spin_unlock(&active_ts_lock); |
41 | } | 41 | } |
42 | 42 | ||
43 | extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) | 43 | extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) |
44 | { | 44 | { |
45 | spin_lock(&inactive_ts_lock); | 45 | spin_lock(&inactive_ts_lock); |
46 | list_add_tail(&ts->ts_list, &inactive_ts_list); | 46 | list_add_tail(&ts->ts_list, &inactive_ts_list); |
47 | iscsit_global->inactive_ts++; | 47 | iscsit_global->inactive_ts++; |
48 | spin_unlock(&inactive_ts_lock); | 48 | spin_unlock(&inactive_ts_lock); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts) | 51 | static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts) |
52 | { | 52 | { |
53 | spin_lock(&active_ts_lock); | 53 | spin_lock(&active_ts_lock); |
54 | list_del(&ts->ts_list); | 54 | list_del(&ts->ts_list); |
55 | iscsit_global->active_ts--; | 55 | iscsit_global->active_ts--; |
56 | spin_unlock(&active_ts_lock); | 56 | spin_unlock(&active_ts_lock); |
57 | } | 57 | } |
58 | 58 | ||
59 | static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) | 59 | static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) |
60 | { | 60 | { |
61 | struct iscsi_thread_set *ts; | 61 | struct iscsi_thread_set *ts; |
62 | 62 | ||
63 | spin_lock(&inactive_ts_lock); | 63 | spin_lock(&inactive_ts_lock); |
64 | if (list_empty(&inactive_ts_list)) { | 64 | if (list_empty(&inactive_ts_list)) { |
65 | spin_unlock(&inactive_ts_lock); | 65 | spin_unlock(&inactive_ts_lock); |
66 | return NULL; | 66 | return NULL; |
67 | } | 67 | } |
68 | 68 | ||
69 | list_for_each_entry(ts, &inactive_ts_list, ts_list) | 69 | list_for_each_entry(ts, &inactive_ts_list, ts_list) |
70 | break; | 70 | break; |
71 | 71 | ||
72 | list_del(&ts->ts_list); | 72 | list_del(&ts->ts_list); |
73 | iscsit_global->inactive_ts--; | 73 | iscsit_global->inactive_ts--; |
74 | spin_unlock(&inactive_ts_lock); | 74 | spin_unlock(&inactive_ts_lock); |
75 | 75 | ||
76 | return ts; | 76 | return ts; |
77 | } | 77 | } |
78 | 78 | ||
79 | extern int iscsi_allocate_thread_sets(u32 thread_pair_count) | 79 | extern int iscsi_allocate_thread_sets(u32 thread_pair_count) |
80 | { | 80 | { |
81 | int allocated_thread_pair_count = 0, i, thread_id; | 81 | int allocated_thread_pair_count = 0, i, thread_id; |
82 | struct iscsi_thread_set *ts = NULL; | 82 | struct iscsi_thread_set *ts = NULL; |
83 | 83 | ||
84 | for (i = 0; i < thread_pair_count; i++) { | 84 | for (i = 0; i < thread_pair_count; i++) { |
85 | ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL); | 85 | ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL); |
86 | if (!ts) { | 86 | if (!ts) { |
87 | pr_err("Unable to allocate memory for" | 87 | pr_err("Unable to allocate memory for" |
88 | " thread set.\n"); | 88 | " thread set.\n"); |
89 | return allocated_thread_pair_count; | 89 | return allocated_thread_pair_count; |
90 | } | 90 | } |
91 | /* | 91 | /* |
92 | * Locate the next available regision in the thread_set_bitmap | 92 | * Locate the next available regision in the thread_set_bitmap |
93 | */ | 93 | */ |
94 | spin_lock(&ts_bitmap_lock); | 94 | spin_lock(&ts_bitmap_lock); |
95 | thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap, | 95 | thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap, |
96 | iscsit_global->ts_bitmap_count, get_order(1)); | 96 | iscsit_global->ts_bitmap_count, get_order(1)); |
97 | spin_unlock(&ts_bitmap_lock); | 97 | spin_unlock(&ts_bitmap_lock); |
98 | if (thread_id < 0) { | 98 | if (thread_id < 0) { |
99 | pr_err("bitmap_find_free_region() failed for" | 99 | pr_err("bitmap_find_free_region() failed for" |
100 | " thread_set_bitmap\n"); | 100 | " thread_set_bitmap\n"); |
101 | kfree(ts); | 101 | kfree(ts); |
102 | return allocated_thread_pair_count; | 102 | return allocated_thread_pair_count; |
103 | } | 103 | } |
104 | 104 | ||
105 | ts->thread_id = thread_id; | 105 | ts->thread_id = thread_id; |
106 | ts->status = ISCSI_THREAD_SET_FREE; | 106 | ts->status = ISCSI_THREAD_SET_FREE; |
107 | INIT_LIST_HEAD(&ts->ts_list); | 107 | INIT_LIST_HEAD(&ts->ts_list); |
108 | spin_lock_init(&ts->ts_state_lock); | 108 | spin_lock_init(&ts->ts_state_lock); |
109 | init_completion(&ts->rx_post_start_comp); | 109 | init_completion(&ts->rx_post_start_comp); |
110 | init_completion(&ts->tx_post_start_comp); | 110 | init_completion(&ts->tx_post_start_comp); |
111 | init_completion(&ts->rx_restart_comp); | 111 | init_completion(&ts->rx_restart_comp); |
112 | init_completion(&ts->tx_restart_comp); | 112 | init_completion(&ts->tx_restart_comp); |
113 | init_completion(&ts->rx_start_comp); | 113 | init_completion(&ts->rx_start_comp); |
114 | init_completion(&ts->tx_start_comp); | 114 | init_completion(&ts->tx_start_comp); |
115 | 115 | ||
116 | ts->create_threads = 1; | 116 | ts->create_threads = 1; |
117 | ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", | 117 | ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", |
118 | ISCSI_TX_THREAD_NAME); | 118 | ISCSI_TX_THREAD_NAME); |
119 | if (IS_ERR(ts->tx_thread)) { | 119 | if (IS_ERR(ts->tx_thread)) { |
120 | dump_stack(); | 120 | dump_stack(); |
121 | pr_err("Unable to start iscsi_target_tx_thread\n"); | 121 | pr_err("Unable to start iscsi_target_tx_thread\n"); |
122 | break; | 122 | break; |
123 | } | 123 | } |
124 | 124 | ||
125 | ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s", | 125 | ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s", |
126 | ISCSI_RX_THREAD_NAME); | 126 | ISCSI_RX_THREAD_NAME); |
127 | if (IS_ERR(ts->rx_thread)) { | 127 | if (IS_ERR(ts->rx_thread)) { |
128 | kthread_stop(ts->tx_thread); | 128 | kthread_stop(ts->tx_thread); |
129 | pr_err("Unable to start iscsi_target_rx_thread\n"); | 129 | pr_err("Unable to start iscsi_target_rx_thread\n"); |
130 | break; | 130 | break; |
131 | } | 131 | } |
132 | ts->create_threads = 0; | 132 | ts->create_threads = 0; |
133 | 133 | ||
134 | iscsi_add_ts_to_inactive_list(ts); | 134 | iscsi_add_ts_to_inactive_list(ts); |
135 | allocated_thread_pair_count++; | 135 | allocated_thread_pair_count++; |
136 | } | 136 | } |
137 | 137 | ||
138 | pr_debug("Spawned %d thread set(s) (%d total threads).\n", | 138 | pr_debug("Spawned %d thread set(s) (%d total threads).\n", |
139 | allocated_thread_pair_count, allocated_thread_pair_count * 2); | 139 | allocated_thread_pair_count, allocated_thread_pair_count * 2); |
140 | return allocated_thread_pair_count; | 140 | return allocated_thread_pair_count; |
141 | } | 141 | } |
142 | 142 | ||
143 | extern void iscsi_deallocate_thread_sets(void) | 143 | extern void iscsi_deallocate_thread_sets(void) |
144 | { | 144 | { |
145 | u32 released_count = 0; | 145 | u32 released_count = 0; |
146 | struct iscsi_thread_set *ts = NULL; | 146 | struct iscsi_thread_set *ts = NULL; |
147 | 147 | ||
148 | while ((ts = iscsi_get_ts_from_inactive_list())) { | 148 | while ((ts = iscsi_get_ts_from_inactive_list())) { |
149 | 149 | ||
150 | spin_lock_bh(&ts->ts_state_lock); | 150 | spin_lock_bh(&ts->ts_state_lock); |
151 | ts->status = ISCSI_THREAD_SET_DIE; | 151 | ts->status = ISCSI_THREAD_SET_DIE; |
152 | spin_unlock_bh(&ts->ts_state_lock); | 152 | spin_unlock_bh(&ts->ts_state_lock); |
153 | 153 | ||
154 | if (ts->rx_thread) { | 154 | if (ts->rx_thread) { |
155 | send_sig(SIGINT, ts->rx_thread, 1); | 155 | send_sig(SIGINT, ts->rx_thread, 1); |
156 | kthread_stop(ts->rx_thread); | 156 | kthread_stop(ts->rx_thread); |
157 | } | 157 | } |
158 | if (ts->tx_thread) { | 158 | if (ts->tx_thread) { |
159 | send_sig(SIGINT, ts->tx_thread, 1); | 159 | send_sig(SIGINT, ts->tx_thread, 1); |
160 | kthread_stop(ts->tx_thread); | 160 | kthread_stop(ts->tx_thread); |
161 | } | 161 | } |
162 | /* | 162 | /* |
163 | * Release this thread_id in the thread_set_bitmap | 163 | * Release this thread_id in the thread_set_bitmap |
164 | */ | 164 | */ |
165 | spin_lock(&ts_bitmap_lock); | 165 | spin_lock(&ts_bitmap_lock); |
166 | bitmap_release_region(iscsit_global->ts_bitmap, | 166 | bitmap_release_region(iscsit_global->ts_bitmap, |
167 | ts->thread_id, get_order(1)); | 167 | ts->thread_id, get_order(1)); |
168 | spin_unlock(&ts_bitmap_lock); | 168 | spin_unlock(&ts_bitmap_lock); |
169 | 169 | ||
170 | released_count++; | 170 | released_count++; |
171 | kfree(ts); | 171 | kfree(ts); |
172 | } | 172 | } |
173 | 173 | ||
174 | if (released_count) | 174 | if (released_count) |
175 | pr_debug("Stopped %d thread set(s) (%d total threads)." | 175 | pr_debug("Stopped %d thread set(s) (%d total threads)." |
176 | "\n", released_count, released_count * 2); | 176 | "\n", released_count, released_count * 2); |
177 | } | 177 | } |
178 | 178 | ||
179 | static void iscsi_deallocate_extra_thread_sets(void) | 179 | static void iscsi_deallocate_extra_thread_sets(void) |
180 | { | 180 | { |
181 | u32 orig_count, released_count = 0; | 181 | u32 orig_count, released_count = 0; |
182 | struct iscsi_thread_set *ts = NULL; | 182 | struct iscsi_thread_set *ts = NULL; |
183 | 183 | ||
184 | orig_count = TARGET_THREAD_SET_COUNT; | 184 | orig_count = TARGET_THREAD_SET_COUNT; |
185 | 185 | ||
186 | while ((iscsit_global->inactive_ts + 1) > orig_count) { | 186 | while ((iscsit_global->inactive_ts + 1) > orig_count) { |
187 | ts = iscsi_get_ts_from_inactive_list(); | 187 | ts = iscsi_get_ts_from_inactive_list(); |
188 | if (!ts) | 188 | if (!ts) |
189 | break; | 189 | break; |
190 | 190 | ||
191 | spin_lock_bh(&ts->ts_state_lock); | 191 | spin_lock_bh(&ts->ts_state_lock); |
192 | ts->status = ISCSI_THREAD_SET_DIE; | 192 | ts->status = ISCSI_THREAD_SET_DIE; |
193 | spin_unlock_bh(&ts->ts_state_lock); | 193 | spin_unlock_bh(&ts->ts_state_lock); |
194 | 194 | ||
195 | if (ts->rx_thread) { | 195 | if (ts->rx_thread) { |
196 | send_sig(SIGINT, ts->rx_thread, 1); | 196 | send_sig(SIGINT, ts->rx_thread, 1); |
197 | kthread_stop(ts->rx_thread); | 197 | kthread_stop(ts->rx_thread); |
198 | } | 198 | } |
199 | if (ts->tx_thread) { | 199 | if (ts->tx_thread) { |
200 | send_sig(SIGINT, ts->tx_thread, 1); | 200 | send_sig(SIGINT, ts->tx_thread, 1); |
201 | kthread_stop(ts->tx_thread); | 201 | kthread_stop(ts->tx_thread); |
202 | } | 202 | } |
203 | /* | 203 | /* |
204 | * Release this thread_id in the thread_set_bitmap | 204 | * Release this thread_id in the thread_set_bitmap |
205 | */ | 205 | */ |
206 | spin_lock(&ts_bitmap_lock); | 206 | spin_lock(&ts_bitmap_lock); |
207 | bitmap_release_region(iscsit_global->ts_bitmap, | 207 | bitmap_release_region(iscsit_global->ts_bitmap, |
208 | ts->thread_id, get_order(1)); | 208 | ts->thread_id, get_order(1)); |
209 | spin_unlock(&ts_bitmap_lock); | 209 | spin_unlock(&ts_bitmap_lock); |
210 | 210 | ||
211 | released_count++; | 211 | released_count++; |
212 | kfree(ts); | 212 | kfree(ts); |
213 | } | 213 | } |
214 | 214 | ||
215 | if (released_count) { | 215 | if (released_count) { |
216 | pr_debug("Stopped %d thread set(s) (%d total threads)." | 216 | pr_debug("Stopped %d thread set(s) (%d total threads)." |
217 | "\n", released_count, released_count * 2); | 217 | "\n", released_count, released_count * 2); |
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) | 221 | void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) |
222 | { | 222 | { |
223 | iscsi_add_ts_to_active_list(ts); | 223 | iscsi_add_ts_to_active_list(ts); |
224 | 224 | ||
225 | spin_lock_bh(&ts->ts_state_lock); | 225 | spin_lock_bh(&ts->ts_state_lock); |
226 | conn->thread_set = ts; | 226 | conn->thread_set = ts; |
227 | ts->conn = conn; | 227 | ts->conn = conn; |
228 | spin_unlock_bh(&ts->ts_state_lock); | 228 | spin_unlock_bh(&ts->ts_state_lock); |
229 | /* | 229 | /* |
230 | * Start up the RX thread and wait on rx_post_start_comp. The RX | 230 | * Start up the RX thread and wait on rx_post_start_comp. The RX |
231 | * Thread will then do the same for the TX Thread in | 231 | * Thread will then do the same for the TX Thread in |
232 | * iscsi_rx_thread_pre_handler(). | 232 | * iscsi_rx_thread_pre_handler(). |
233 | */ | 233 | */ |
234 | complete(&ts->rx_start_comp); | 234 | complete(&ts->rx_start_comp); |
235 | wait_for_completion(&ts->rx_post_start_comp); | 235 | wait_for_completion(&ts->rx_post_start_comp); |
236 | } | 236 | } |
237 | 237 | ||
238 | struct iscsi_thread_set *iscsi_get_thread_set(void) | 238 | struct iscsi_thread_set *iscsi_get_thread_set(void) |
239 | { | 239 | { |
240 | int allocate_ts = 0; | 240 | int allocate_ts = 0; |
241 | struct completion comp; | 241 | struct completion comp; |
242 | struct iscsi_thread_set *ts = NULL; | 242 | struct iscsi_thread_set *ts = NULL; |
243 | /* | 243 | /* |
244 | * If no inactive thread set is available on the first call to | 244 | * If no inactive thread set is available on the first call to |
245 | * iscsi_get_ts_from_inactive_list(), sleep for a second and | 245 | * iscsi_get_ts_from_inactive_list(), sleep for a second and |
246 | * try again. If still none are available after two attempts, | 246 | * try again. If still none are available after two attempts, |
247 | * allocate a set ourselves. | 247 | * allocate a set ourselves. |
248 | */ | 248 | */ |
249 | get_set: | 249 | get_set: |
250 | ts = iscsi_get_ts_from_inactive_list(); | 250 | ts = iscsi_get_ts_from_inactive_list(); |
251 | if (!ts) { | 251 | if (!ts) { |
252 | if (allocate_ts == 2) | 252 | if (allocate_ts == 2) |
253 | iscsi_allocate_thread_sets(1); | 253 | iscsi_allocate_thread_sets(1); |
254 | 254 | ||
255 | init_completion(&comp); | 255 | init_completion(&comp); |
256 | wait_for_completion_timeout(&comp, 1 * HZ); | 256 | wait_for_completion_timeout(&comp, 1 * HZ); |
257 | 257 | ||
258 | allocate_ts++; | 258 | allocate_ts++; |
259 | goto get_set; | 259 | goto get_set; |
260 | } | 260 | } |
261 | 261 | ||
262 | ts->delay_inactive = 1; | 262 | ts->delay_inactive = 1; |
263 | ts->signal_sent = 0; | 263 | ts->signal_sent = 0; |
264 | ts->thread_count = 2; | 264 | ts->thread_count = 2; |
265 | init_completion(&ts->rx_restart_comp); | 265 | init_completion(&ts->rx_restart_comp); |
266 | init_completion(&ts->tx_restart_comp); | 266 | init_completion(&ts->tx_restart_comp); |
267 | 267 | ||
268 | return ts; | 268 | return ts; |
269 | } | 269 | } |
270 | 270 | ||
271 | void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear) | 271 | void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear) |
272 | { | 272 | { |
273 | struct iscsi_thread_set *ts = NULL; | 273 | struct iscsi_thread_set *ts = NULL; |
274 | 274 | ||
275 | if (!conn->thread_set) { | 275 | if (!conn->thread_set) { |
276 | pr_err("struct iscsi_conn->thread_set is NULL\n"); | 276 | pr_err("struct iscsi_conn->thread_set is NULL\n"); |
277 | return; | 277 | return; |
278 | } | 278 | } |
279 | ts = conn->thread_set; | 279 | ts = conn->thread_set; |
280 | 280 | ||
281 | spin_lock_bh(&ts->ts_state_lock); | 281 | spin_lock_bh(&ts->ts_state_lock); |
282 | ts->thread_clear &= ~thread_clear; | 282 | ts->thread_clear &= ~thread_clear; |
283 | 283 | ||
284 | if ((thread_clear & ISCSI_CLEAR_RX_THREAD) && | 284 | if ((thread_clear & ISCSI_CLEAR_RX_THREAD) && |
285 | (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD)) | 285 | (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD)) |
286 | complete(&ts->rx_restart_comp); | 286 | complete(&ts->rx_restart_comp); |
287 | else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) && | 287 | else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) && |
288 | (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD)) | 288 | (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD)) |
289 | complete(&ts->tx_restart_comp); | 289 | complete(&ts->tx_restart_comp); |
290 | spin_unlock_bh(&ts->ts_state_lock); | 290 | spin_unlock_bh(&ts->ts_state_lock); |
291 | } | 291 | } |
292 | 292 | ||
293 | void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent) | 293 | void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent) |
294 | { | 294 | { |
295 | struct iscsi_thread_set *ts = NULL; | 295 | struct iscsi_thread_set *ts = NULL; |
296 | 296 | ||
297 | if (!conn->thread_set) { | 297 | if (!conn->thread_set) { |
298 | pr_err("struct iscsi_conn->thread_set is NULL\n"); | 298 | pr_err("struct iscsi_conn->thread_set is NULL\n"); |
299 | return; | 299 | return; |
300 | } | 300 | } |
301 | ts = conn->thread_set; | 301 | ts = conn->thread_set; |
302 | 302 | ||
303 | spin_lock_bh(&ts->ts_state_lock); | 303 | spin_lock_bh(&ts->ts_state_lock); |
304 | ts->signal_sent |= signal_sent; | 304 | ts->signal_sent |= signal_sent; |
305 | spin_unlock_bh(&ts->ts_state_lock); | 305 | spin_unlock_bh(&ts->ts_state_lock); |
306 | } | 306 | } |
307 | 307 | ||
308 | int iscsi_release_thread_set(struct iscsi_conn *conn) | 308 | int iscsi_release_thread_set(struct iscsi_conn *conn) |
309 | { | 309 | { |
310 | int thread_called = 0; | 310 | int thread_called = 0; |
311 | struct iscsi_thread_set *ts = NULL; | 311 | struct iscsi_thread_set *ts = NULL; |
312 | 312 | ||
313 | if (!conn || !conn->thread_set) { | 313 | if (!conn || !conn->thread_set) { |
314 | pr_err("connection or thread set pointer is NULL\n"); | 314 | pr_err("connection or thread set pointer is NULL\n"); |
315 | BUG(); | 315 | BUG(); |
316 | } | 316 | } |
317 | ts = conn->thread_set; | 317 | ts = conn->thread_set; |
318 | 318 | ||
319 | spin_lock_bh(&ts->ts_state_lock); | 319 | spin_lock_bh(&ts->ts_state_lock); |
320 | ts->status = ISCSI_THREAD_SET_RESET; | 320 | ts->status = ISCSI_THREAD_SET_RESET; |
321 | 321 | ||
322 | if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME, | 322 | if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME, |
323 | strlen(ISCSI_RX_THREAD_NAME))) | 323 | strlen(ISCSI_RX_THREAD_NAME))) |
324 | thread_called = ISCSI_RX_THREAD; | 324 | thread_called = ISCSI_RX_THREAD; |
325 | else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME, | 325 | else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME, |
326 | strlen(ISCSI_TX_THREAD_NAME))) | 326 | strlen(ISCSI_TX_THREAD_NAME))) |
327 | thread_called = ISCSI_TX_THREAD; | 327 | thread_called = ISCSI_TX_THREAD; |
328 | 328 | ||
329 | if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) && | 329 | if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) && |
330 | (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) { | 330 | (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) { |
331 | 331 | ||
332 | if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) { | 332 | if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) { |
333 | send_sig(SIGINT, ts->rx_thread, 1); | 333 | send_sig(SIGINT, ts->rx_thread, 1); |
334 | ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; | 334 | ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; |
335 | } | 335 | } |
336 | ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD; | 336 | ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD; |
337 | spin_unlock_bh(&ts->ts_state_lock); | 337 | spin_unlock_bh(&ts->ts_state_lock); |
338 | wait_for_completion(&ts->rx_restart_comp); | 338 | wait_for_completion(&ts->rx_restart_comp); |
339 | spin_lock_bh(&ts->ts_state_lock); | 339 | spin_lock_bh(&ts->ts_state_lock); |
340 | ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD; | 340 | ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD; |
341 | } | 341 | } |
342 | if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) && | 342 | if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) && |
343 | (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) { | 343 | (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) { |
344 | 344 | ||
345 | if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) { | 345 | if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) { |
346 | send_sig(SIGINT, ts->tx_thread, 1); | 346 | send_sig(SIGINT, ts->tx_thread, 1); |
347 | ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; | 347 | ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; |
348 | } | 348 | } |
349 | ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD; | 349 | ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD; |
350 | spin_unlock_bh(&ts->ts_state_lock); | 350 | spin_unlock_bh(&ts->ts_state_lock); |
351 | wait_for_completion(&ts->tx_restart_comp); | 351 | wait_for_completion(&ts->tx_restart_comp); |
352 | spin_lock_bh(&ts->ts_state_lock); | 352 | spin_lock_bh(&ts->ts_state_lock); |
353 | ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD; | 353 | ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD; |
354 | } | 354 | } |
355 | 355 | ||
356 | ts->conn = NULL; | 356 | ts->conn = NULL; |
357 | ts->status = ISCSI_THREAD_SET_FREE; | 357 | ts->status = ISCSI_THREAD_SET_FREE; |
358 | spin_unlock_bh(&ts->ts_state_lock); | 358 | spin_unlock_bh(&ts->ts_state_lock); |
359 | 359 | ||
360 | return 0; | 360 | return 0; |
361 | } | 361 | } |
362 | 362 | ||
363 | int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn) | 363 | int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn) |
364 | { | 364 | { |
365 | struct iscsi_thread_set *ts; | 365 | struct iscsi_thread_set *ts; |
366 | 366 | ||
367 | if (!conn->thread_set) | 367 | if (!conn->thread_set) |
368 | return -1; | 368 | return -1; |
369 | ts = conn->thread_set; | 369 | ts = conn->thread_set; |
370 | 370 | ||
371 | spin_lock_bh(&ts->ts_state_lock); | 371 | spin_lock_bh(&ts->ts_state_lock); |
372 | if (ts->status != ISCSI_THREAD_SET_ACTIVE) { | 372 | if (ts->status != ISCSI_THREAD_SET_ACTIVE) { |
373 | spin_unlock_bh(&ts->ts_state_lock); | 373 | spin_unlock_bh(&ts->ts_state_lock); |
374 | return -1; | 374 | return -1; |
375 | } | 375 | } |
376 | 376 | ||
377 | if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) { | 377 | if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) { |
378 | send_sig(SIGINT, ts->tx_thread, 1); | 378 | send_sig(SIGINT, ts->tx_thread, 1); |
379 | ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; | 379 | ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; |
380 | } | 380 | } |
381 | if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) { | 381 | if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) { |
382 | send_sig(SIGINT, ts->rx_thread, 1); | 382 | send_sig(SIGINT, ts->rx_thread, 1); |
383 | ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; | 383 | ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; |
384 | } | 384 | } |
385 | spin_unlock_bh(&ts->ts_state_lock); | 385 | spin_unlock_bh(&ts->ts_state_lock); |
386 | 386 | ||
387 | return 0; | 387 | return 0; |
388 | } | 388 | } |
389 | 389 | ||
390 | static void iscsi_check_to_add_additional_sets(void) | 390 | static void iscsi_check_to_add_additional_sets(void) |
391 | { | 391 | { |
392 | int thread_sets_add; | 392 | int thread_sets_add; |
393 | 393 | ||
394 | spin_lock(&inactive_ts_lock); | 394 | spin_lock(&inactive_ts_lock); |
395 | thread_sets_add = iscsit_global->inactive_ts; | 395 | thread_sets_add = iscsit_global->inactive_ts; |
396 | spin_unlock(&inactive_ts_lock); | 396 | spin_unlock(&inactive_ts_lock); |
397 | if (thread_sets_add == 1) | 397 | if (thread_sets_add == 1) |
398 | iscsi_allocate_thread_sets(1); | 398 | iscsi_allocate_thread_sets(1); |
399 | } | 399 | } |
400 | 400 | ||
401 | static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) | 401 | static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) |
402 | { | 402 | { |
403 | spin_lock_bh(&ts->ts_state_lock); | 403 | spin_lock_bh(&ts->ts_state_lock); |
404 | if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) { | 404 | if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) { |
405 | spin_unlock_bh(&ts->ts_state_lock); | 405 | spin_unlock_bh(&ts->ts_state_lock); |
406 | return -1; | 406 | return -1; |
407 | } | 407 | } |
408 | spin_unlock_bh(&ts->ts_state_lock); | 408 | spin_unlock_bh(&ts->ts_state_lock); |
409 | 409 | ||
410 | return 0; | 410 | return 0; |
411 | } | 411 | } |
412 | 412 | ||
413 | struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) | 413 | struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) |
414 | { | 414 | { |
415 | int ret; | 415 | int ret; |
416 | 416 | ||
417 | spin_lock_bh(&ts->ts_state_lock); | 417 | spin_lock_bh(&ts->ts_state_lock); |
418 | if (ts->create_threads) { | 418 | if (ts->create_threads) { |
419 | spin_unlock_bh(&ts->ts_state_lock); | 419 | spin_unlock_bh(&ts->ts_state_lock); |
420 | goto sleep; | 420 | goto sleep; |
421 | } | 421 | } |
422 | 422 | ||
423 | flush_signals(current); | 423 | flush_signals(current); |
424 | 424 | ||
425 | if (ts->delay_inactive && (--ts->thread_count == 0)) { | 425 | if (ts->delay_inactive && (--ts->thread_count == 0)) { |
426 | spin_unlock_bh(&ts->ts_state_lock); | 426 | spin_unlock_bh(&ts->ts_state_lock); |
427 | iscsi_del_ts_from_active_list(ts); | 427 | iscsi_del_ts_from_active_list(ts); |
428 | 428 | ||
429 | if (!iscsit_global->in_shutdown) | 429 | if (!iscsit_global->in_shutdown) |
430 | iscsi_deallocate_extra_thread_sets(); | 430 | iscsi_deallocate_extra_thread_sets(); |
431 | 431 | ||
432 | iscsi_add_ts_to_inactive_list(ts); | 432 | iscsi_add_ts_to_inactive_list(ts); |
433 | spin_lock_bh(&ts->ts_state_lock); | 433 | spin_lock_bh(&ts->ts_state_lock); |
434 | } | 434 | } |
435 | 435 | ||
436 | if ((ts->status == ISCSI_THREAD_SET_RESET) && | 436 | if ((ts->status == ISCSI_THREAD_SET_RESET) && |
437 | (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) | 437 | (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) |
438 | complete(&ts->rx_restart_comp); | 438 | complete(&ts->rx_restart_comp); |
439 | 439 | ||
440 | ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD; | 440 | ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD; |
441 | spin_unlock_bh(&ts->ts_state_lock); | 441 | spin_unlock_bh(&ts->ts_state_lock); |
442 | sleep: | 442 | sleep: |
443 | ret = wait_for_completion_interruptible(&ts->rx_start_comp); | 443 | ret = wait_for_completion_interruptible(&ts->rx_start_comp); |
444 | if (ret != 0) | 444 | if (ret != 0) |
445 | return NULL; | 445 | return NULL; |
446 | 446 | ||
447 | if (iscsi_signal_thread_pre_handler(ts) < 0) | 447 | if (iscsi_signal_thread_pre_handler(ts) < 0) |
448 | return NULL; | 448 | return NULL; |
449 | 449 | ||
450 | if (!ts->conn) { | 450 | if (!ts->conn) { |
451 | pr_err("struct iscsi_thread_set->conn is NULL for" | 451 | pr_err("struct iscsi_thread_set->conn is NULL for" |
452 | " thread_id: %d, going back to sleep\n", ts->thread_id); | 452 | " thread_id: %d, going back to sleep\n", ts->thread_id); |
453 | goto sleep; | 453 | goto sleep; |
454 | } | 454 | } |
455 | iscsi_check_to_add_additional_sets(); | 455 | iscsi_check_to_add_additional_sets(); |
456 | /* | 456 | /* |
457 | * The RX Thread starts up the TX Thread and sleeps. | 457 | * The RX Thread starts up the TX Thread and sleeps. |
458 | */ | 458 | */ |
459 | ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; | 459 | ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; |
460 | complete(&ts->tx_start_comp); | 460 | complete(&ts->tx_start_comp); |
461 | wait_for_completion(&ts->tx_post_start_comp); | 461 | wait_for_completion(&ts->tx_post_start_comp); |
462 | 462 | ||
463 | return ts->conn; | 463 | return ts->conn; |
464 | } | 464 | } |
465 | 465 | ||
466 | struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) | 466 | struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) |
467 | { | 467 | { |
468 | int ret; | 468 | int ret; |
469 | 469 | ||
470 | spin_lock_bh(&ts->ts_state_lock); | 470 | spin_lock_bh(&ts->ts_state_lock); |
471 | if (ts->create_threads) { | 471 | if (ts->create_threads) { |
472 | spin_unlock_bh(&ts->ts_state_lock); | 472 | spin_unlock_bh(&ts->ts_state_lock); |
473 | goto sleep; | 473 | goto sleep; |
474 | } | 474 | } |
475 | 475 | ||
476 | flush_signals(current); | 476 | flush_signals(current); |
477 | 477 | ||
478 | if (ts->delay_inactive && (--ts->thread_count == 0)) { | 478 | if (ts->delay_inactive && (--ts->thread_count == 0)) { |
479 | spin_unlock_bh(&ts->ts_state_lock); | 479 | spin_unlock_bh(&ts->ts_state_lock); |
480 | iscsi_del_ts_from_active_list(ts); | 480 | iscsi_del_ts_from_active_list(ts); |
481 | 481 | ||
482 | if (!iscsit_global->in_shutdown) | 482 | if (!iscsit_global->in_shutdown) |
483 | iscsi_deallocate_extra_thread_sets(); | 483 | iscsi_deallocate_extra_thread_sets(); |
484 | 484 | ||
485 | iscsi_add_ts_to_inactive_list(ts); | 485 | iscsi_add_ts_to_inactive_list(ts); |
486 | spin_lock_bh(&ts->ts_state_lock); | 486 | spin_lock_bh(&ts->ts_state_lock); |
487 | } | 487 | } |
488 | if ((ts->status == ISCSI_THREAD_SET_RESET) && | 488 | if ((ts->status == ISCSI_THREAD_SET_RESET) && |
489 | (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) | 489 | (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) |
490 | complete(&ts->tx_restart_comp); | 490 | complete(&ts->tx_restart_comp); |
491 | 491 | ||
492 | ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD; | 492 | ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD; |
493 | spin_unlock_bh(&ts->ts_state_lock); | 493 | spin_unlock_bh(&ts->ts_state_lock); |
494 | sleep: | 494 | sleep: |
495 | ret = wait_for_completion_interruptible(&ts->tx_start_comp); | 495 | ret = wait_for_completion_interruptible(&ts->tx_start_comp); |
496 | if (ret != 0) | 496 | if (ret != 0) |
497 | return NULL; | 497 | return NULL; |
498 | 498 | ||
499 | if (iscsi_signal_thread_pre_handler(ts) < 0) | 499 | if (iscsi_signal_thread_pre_handler(ts) < 0) |
500 | return NULL; | 500 | return NULL; |
501 | 501 | ||
502 | if (!ts->conn) { | 502 | if (!ts->conn) { |
503 | pr_err("struct iscsi_thread_set->conn is NULL for " | 503 | pr_err("struct iscsi_thread_set->conn is NULL for " |
504 | " thread_id: %d, going back to sleep\n", | 504 | " thread_id: %d, going back to sleep\n", |
505 | ts->thread_id); | 505 | ts->thread_id); |
506 | goto sleep; | 506 | goto sleep; |
507 | } | 507 | } |
508 | 508 | ||
509 | iscsi_check_to_add_additional_sets(); | 509 | iscsi_check_to_add_additional_sets(); |
510 | /* | 510 | /* |
511 | * From the TX thread, up the tx_post_start_comp that the RX Thread is | 511 | * From the TX thread, up the tx_post_start_comp that the RX Thread is |
512 | * sleeping on in iscsi_rx_thread_pre_handler(), then up the | 512 | * sleeping on in iscsi_rx_thread_pre_handler(), then up the |
513 | * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on. | 513 | * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on. |
514 | */ | 514 | */ |
515 | ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; | 515 | ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; |
516 | complete(&ts->tx_post_start_comp); | 516 | complete(&ts->tx_post_start_comp); |
517 | complete(&ts->rx_post_start_comp); | 517 | complete(&ts->rx_post_start_comp); |
518 | 518 | ||
519 | spin_lock_bh(&ts->ts_state_lock); | 519 | spin_lock_bh(&ts->ts_state_lock); |
520 | ts->status = ISCSI_THREAD_SET_ACTIVE; | 520 | ts->status = ISCSI_THREAD_SET_ACTIVE; |
521 | spin_unlock_bh(&ts->ts_state_lock); | 521 | spin_unlock_bh(&ts->ts_state_lock); |
522 | 522 | ||
523 | return ts->conn; | 523 | return ts->conn; |
524 | } | 524 | } |
525 | 525 | ||
526 | int iscsi_thread_set_init(void) | 526 | int iscsi_thread_set_init(void) |
527 | { | 527 | { |
528 | int size; | 528 | int size; |
529 | 529 | ||
530 | iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS; | 530 | iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS; |
531 | 531 | ||
532 | size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long); | 532 | size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long); |
533 | iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL); | 533 | iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL); |
534 | if (!iscsit_global->ts_bitmap) { | 534 | if (!iscsit_global->ts_bitmap) { |
535 | pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); | 535 | pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); |
536 | return -ENOMEM; | 536 | return -ENOMEM; |
537 | } | 537 | } |
538 | 538 | ||
539 | spin_lock_init(&active_ts_lock); | ||
540 | spin_lock_init(&inactive_ts_lock); | ||
541 | spin_lock_init(&ts_bitmap_lock); | ||
542 | INIT_LIST_HEAD(&active_ts_list); | ||
543 | INIT_LIST_HEAD(&inactive_ts_list); | ||
544 | |||
545 | return 0; | 539 | return 0; |
546 | } | 540 | } |
547 | 541 | ||
548 | void iscsi_thread_set_free(void) | 542 | void iscsi_thread_set_free(void) |
549 | { | 543 | { |
550 | kfree(iscsit_global->ts_bitmap); | 544 | kfree(iscsit_global->ts_bitmap); |
551 | } | 545 | } |
552 | 546 |
drivers/target/target_core_configfs.c
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * Filename: target_core_configfs.c | 2 | * Filename: target_core_configfs.c |
3 | * | 3 | * |
4 | * This file contains ConfigFS logic for the Generic Target Engine project. | 4 | * This file contains ConfigFS logic for the Generic Target Engine project. |
5 | * | 5 | * |
6 | * Copyright (c) 2008-2011 Rising Tide Systems | 6 | * Copyright (c) 2008-2011 Rising Tide Systems |
7 | * Copyright (c) 2008-2011 Linux-iSCSI.org | 7 | * Copyright (c) 2008-2011 Linux-iSCSI.org |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
11 | * based on configfs Copyright (C) 2005 Oracle. All rights reserved. | 11 | * based on configfs Copyright (C) 2005 Oracle. All rights reserved. |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
15 | * the Free Software Foundation; either version 2 of the License, or | 15 | * the Free Software Foundation; either version 2 of the License, or |
16 | * (at your option) any later version. | 16 | * (at your option) any later version. |
17 | * | 17 | * |
18 | * This program is distributed in the hope that it will be useful, | 18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
22 | ****************************************************************************/ | 22 | ****************************************************************************/ |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
26 | #include <generated/utsrelease.h> | 26 | #include <generated/utsrelease.h> |
27 | #include <linux/utsname.h> | 27 | #include <linux/utsname.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | #include <linux/namei.h> | 30 | #include <linux/namei.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/unistd.h> | 34 | #include <linux/unistd.h> |
35 | #include <linux/string.h> | 35 | #include <linux/string.h> |
36 | #include <linux/parser.h> | 36 | #include <linux/parser.h> |
37 | #include <linux/syscalls.h> | 37 | #include <linux/syscalls.h> |
38 | #include <linux/configfs.h> | 38 | #include <linux/configfs.h> |
39 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
40 | 40 | ||
41 | #include <target/target_core_base.h> | 41 | #include <target/target_core_base.h> |
42 | #include <target/target_core_backend.h> | 42 | #include <target/target_core_backend.h> |
43 | #include <target/target_core_fabric.h> | 43 | #include <target/target_core_fabric.h> |
44 | #include <target/target_core_fabric_configfs.h> | 44 | #include <target/target_core_fabric_configfs.h> |
45 | #include <target/target_core_configfs.h> | 45 | #include <target/target_core_configfs.h> |
46 | #include <target/configfs_macros.h> | 46 | #include <target/configfs_macros.h> |
47 | 47 | ||
48 | #include "target_core_internal.h" | 48 | #include "target_core_internal.h" |
49 | #include "target_core_alua.h" | 49 | #include "target_core_alua.h" |
50 | #include "target_core_pr.h" | 50 | #include "target_core_pr.h" |
51 | #include "target_core_rd.h" | 51 | #include "target_core_rd.h" |
52 | 52 | ||
53 | extern struct t10_alua_lu_gp *default_lu_gp; | 53 | extern struct t10_alua_lu_gp *default_lu_gp; |
54 | 54 | ||
55 | static struct list_head g_tf_list; | 55 | static LIST_HEAD(g_tf_list); |
56 | static struct mutex g_tf_lock; | 56 | static DEFINE_MUTEX(g_tf_lock); |
57 | 57 | ||
58 | struct target_core_configfs_attribute { | 58 | struct target_core_configfs_attribute { |
59 | struct configfs_attribute attr; | 59 | struct configfs_attribute attr; |
60 | ssize_t (*show)(void *, char *); | 60 | ssize_t (*show)(void *, char *); |
61 | ssize_t (*store)(void *, const char *, size_t); | 61 | ssize_t (*store)(void *, const char *, size_t); |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static struct config_group target_core_hbagroup; | 64 | static struct config_group target_core_hbagroup; |
65 | static struct config_group alua_group; | 65 | static struct config_group alua_group; |
66 | static struct config_group alua_lu_gps_group; | 66 | static struct config_group alua_lu_gps_group; |
67 | 67 | ||
68 | static inline struct se_hba * | 68 | static inline struct se_hba * |
69 | item_to_hba(struct config_item *item) | 69 | item_to_hba(struct config_item *item) |
70 | { | 70 | { |
71 | return container_of(to_config_group(item), struct se_hba, hba_group); | 71 | return container_of(to_config_group(item), struct se_hba, hba_group); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Attributes for /sys/kernel/config/target/ | 75 | * Attributes for /sys/kernel/config/target/ |
76 | */ | 76 | */ |
77 | static ssize_t target_core_attr_show(struct config_item *item, | 77 | static ssize_t target_core_attr_show(struct config_item *item, |
78 | struct configfs_attribute *attr, | 78 | struct configfs_attribute *attr, |
79 | char *page) | 79 | char *page) |
80 | { | 80 | { |
81 | return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s" | 81 | return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s" |
82 | " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION, | 82 | " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION, |
83 | utsname()->sysname, utsname()->machine); | 83 | utsname()->sysname, utsname()->machine); |
84 | } | 84 | } |
85 | 85 | ||
86 | static struct configfs_item_operations target_core_fabric_item_ops = { | 86 | static struct configfs_item_operations target_core_fabric_item_ops = { |
87 | .show_attribute = target_core_attr_show, | 87 | .show_attribute = target_core_attr_show, |
88 | }; | 88 | }; |
89 | 89 | ||
90 | static struct configfs_attribute target_core_item_attr_version = { | 90 | static struct configfs_attribute target_core_item_attr_version = { |
91 | .ca_owner = THIS_MODULE, | 91 | .ca_owner = THIS_MODULE, |
92 | .ca_name = "version", | 92 | .ca_name = "version", |
93 | .ca_mode = S_IRUGO, | 93 | .ca_mode = S_IRUGO, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static struct target_fabric_configfs *target_core_get_fabric( | 96 | static struct target_fabric_configfs *target_core_get_fabric( |
97 | const char *name) | 97 | const char *name) |
98 | { | 98 | { |
99 | struct target_fabric_configfs *tf; | 99 | struct target_fabric_configfs *tf; |
100 | 100 | ||
101 | if (!name) | 101 | if (!name) |
102 | return NULL; | 102 | return NULL; |
103 | 103 | ||
104 | mutex_lock(&g_tf_lock); | 104 | mutex_lock(&g_tf_lock); |
105 | list_for_each_entry(tf, &g_tf_list, tf_list) { | 105 | list_for_each_entry(tf, &g_tf_list, tf_list) { |
106 | if (!strcmp(tf->tf_name, name)) { | 106 | if (!strcmp(tf->tf_name, name)) { |
107 | atomic_inc(&tf->tf_access_cnt); | 107 | atomic_inc(&tf->tf_access_cnt); |
108 | mutex_unlock(&g_tf_lock); | 108 | mutex_unlock(&g_tf_lock); |
109 | return tf; | 109 | return tf; |
110 | } | 110 | } |
111 | } | 111 | } |
112 | mutex_unlock(&g_tf_lock); | 112 | mutex_unlock(&g_tf_lock); |
113 | 113 | ||
114 | return NULL; | 114 | return NULL; |
115 | } | 115 | } |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * Called from struct target_core_group_ops->make_group() | 118 | * Called from struct target_core_group_ops->make_group() |
119 | */ | 119 | */ |
120 | static struct config_group *target_core_register_fabric( | 120 | static struct config_group *target_core_register_fabric( |
121 | struct config_group *group, | 121 | struct config_group *group, |
122 | const char *name) | 122 | const char *name) |
123 | { | 123 | { |
124 | struct target_fabric_configfs *tf; | 124 | struct target_fabric_configfs *tf; |
125 | int ret; | 125 | int ret; |
126 | 126 | ||
127 | pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:" | 127 | pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:" |
128 | " %s\n", group, name); | 128 | " %s\n", group, name); |
129 | /* | 129 | /* |
130 | * Below are some hardcoded request_module() calls to automatically | 130 | * Below are some hardcoded request_module() calls to automatically |
131 | * local fabric modules when the following is called: | 131 | * local fabric modules when the following is called: |
132 | * | 132 | * |
133 | * mkdir -p /sys/kernel/config/target/$MODULE_NAME | 133 | * mkdir -p /sys/kernel/config/target/$MODULE_NAME |
134 | * | 134 | * |
135 | * Note that this does not limit which TCM fabric module can be | 135 | * Note that this does not limit which TCM fabric module can be |
136 | * registered, but simply provids auto loading logic for modules with | 136 | * registered, but simply provids auto loading logic for modules with |
137 | * mkdir(2) system calls with known TCM fabric modules. | 137 | * mkdir(2) system calls with known TCM fabric modules. |
138 | */ | 138 | */ |
139 | if (!strncmp(name, "iscsi", 5)) { | 139 | if (!strncmp(name, "iscsi", 5)) { |
140 | /* | 140 | /* |
141 | * Automatically load the LIO Target fabric module when the | 141 | * Automatically load the LIO Target fabric module when the |
142 | * following is called: | 142 | * following is called: |
143 | * | 143 | * |
144 | * mkdir -p $CONFIGFS/target/iscsi | 144 | * mkdir -p $CONFIGFS/target/iscsi |
145 | */ | 145 | */ |
146 | ret = request_module("iscsi_target_mod"); | 146 | ret = request_module("iscsi_target_mod"); |
147 | if (ret < 0) { | 147 | if (ret < 0) { |
148 | pr_err("request_module() failed for" | 148 | pr_err("request_module() failed for" |
149 | " iscsi_target_mod.ko: %d\n", ret); | 149 | " iscsi_target_mod.ko: %d\n", ret); |
150 | return ERR_PTR(-EINVAL); | 150 | return ERR_PTR(-EINVAL); |
151 | } | 151 | } |
152 | } else if (!strncmp(name, "loopback", 8)) { | 152 | } else if (!strncmp(name, "loopback", 8)) { |
153 | /* | 153 | /* |
154 | * Automatically load the tcm_loop fabric module when the | 154 | * Automatically load the tcm_loop fabric module when the |
155 | * following is called: | 155 | * following is called: |
156 | * | 156 | * |
157 | * mkdir -p $CONFIGFS/target/loopback | 157 | * mkdir -p $CONFIGFS/target/loopback |
158 | */ | 158 | */ |
159 | ret = request_module("tcm_loop"); | 159 | ret = request_module("tcm_loop"); |
160 | if (ret < 0) { | 160 | if (ret < 0) { |
161 | pr_err("request_module() failed for" | 161 | pr_err("request_module() failed for" |
162 | " tcm_loop.ko: %d\n", ret); | 162 | " tcm_loop.ko: %d\n", ret); |
163 | return ERR_PTR(-EINVAL); | 163 | return ERR_PTR(-EINVAL); |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | tf = target_core_get_fabric(name); | 167 | tf = target_core_get_fabric(name); |
168 | if (!tf) { | 168 | if (!tf) { |
169 | pr_err("target_core_get_fabric() failed for %s\n", | 169 | pr_err("target_core_get_fabric() failed for %s\n", |
170 | name); | 170 | name); |
171 | return ERR_PTR(-EINVAL); | 171 | return ERR_PTR(-EINVAL); |
172 | } | 172 | } |
173 | pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:" | 173 | pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:" |
174 | " %s\n", tf->tf_name); | 174 | " %s\n", tf->tf_name); |
175 | /* | 175 | /* |
176 | * On a successful target_core_get_fabric() look, the returned | 176 | * On a successful target_core_get_fabric() look, the returned |
177 | * struct target_fabric_configfs *tf will contain a usage reference. | 177 | * struct target_fabric_configfs *tf will contain a usage reference. |
178 | */ | 178 | */ |
179 | pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", | 179 | pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", |
180 | &TF_CIT_TMPL(tf)->tfc_wwn_cit); | 180 | &TF_CIT_TMPL(tf)->tfc_wwn_cit); |
181 | 181 | ||
182 | tf->tf_group.default_groups = tf->tf_default_groups; | 182 | tf->tf_group.default_groups = tf->tf_default_groups; |
183 | tf->tf_group.default_groups[0] = &tf->tf_disc_group; | 183 | tf->tf_group.default_groups[0] = &tf->tf_disc_group; |
184 | tf->tf_group.default_groups[1] = NULL; | 184 | tf->tf_group.default_groups[1] = NULL; |
185 | 185 | ||
186 | config_group_init_type_name(&tf->tf_group, name, | 186 | config_group_init_type_name(&tf->tf_group, name, |
187 | &TF_CIT_TMPL(tf)->tfc_wwn_cit); | 187 | &TF_CIT_TMPL(tf)->tfc_wwn_cit); |
188 | config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", | 188 | config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", |
189 | &TF_CIT_TMPL(tf)->tfc_discovery_cit); | 189 | &TF_CIT_TMPL(tf)->tfc_discovery_cit); |
190 | 190 | ||
191 | pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" | 191 | pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" |
192 | " %s\n", tf->tf_group.cg_item.ci_name); | 192 | " %s\n", tf->tf_group.cg_item.ci_name); |
193 | /* | 193 | /* |
194 | * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item() | 194 | * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item() |
195 | */ | 195 | */ |
196 | tf->tf_ops.tf_subsys = tf->tf_subsys; | 196 | tf->tf_ops.tf_subsys = tf->tf_subsys; |
197 | tf->tf_fabric = &tf->tf_group.cg_item; | 197 | tf->tf_fabric = &tf->tf_group.cg_item; |
198 | pr_debug("Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric" | 198 | pr_debug("Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric" |
199 | " for %s\n", name); | 199 | " for %s\n", name); |
200 | 200 | ||
201 | return &tf->tf_group; | 201 | return &tf->tf_group; |
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | /* |
205 | * Called from struct target_core_group_ops->drop_item() | 205 | * Called from struct target_core_group_ops->drop_item() |
206 | */ | 206 | */ |
207 | static void target_core_deregister_fabric( | 207 | static void target_core_deregister_fabric( |
208 | struct config_group *group, | 208 | struct config_group *group, |
209 | struct config_item *item) | 209 | struct config_item *item) |
210 | { | 210 | { |
211 | struct target_fabric_configfs *tf = container_of( | 211 | struct target_fabric_configfs *tf = container_of( |
212 | to_config_group(item), struct target_fabric_configfs, tf_group); | 212 | to_config_group(item), struct target_fabric_configfs, tf_group); |
213 | struct config_group *tf_group; | 213 | struct config_group *tf_group; |
214 | struct config_item *df_item; | 214 | struct config_item *df_item; |
215 | int i; | 215 | int i; |
216 | 216 | ||
217 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Looking up %s in" | 217 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Looking up %s in" |
218 | " tf list\n", config_item_name(item)); | 218 | " tf list\n", config_item_name(item)); |
219 | 219 | ||
220 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> located fabric:" | 220 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> located fabric:" |
221 | " %s\n", tf->tf_name); | 221 | " %s\n", tf->tf_name); |
222 | atomic_dec(&tf->tf_access_cnt); | 222 | atomic_dec(&tf->tf_access_cnt); |
223 | 223 | ||
224 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing" | 224 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing" |
225 | " tf->tf_fabric for %s\n", tf->tf_name); | 225 | " tf->tf_fabric for %s\n", tf->tf_name); |
226 | tf->tf_fabric = NULL; | 226 | tf->tf_fabric = NULL; |
227 | 227 | ||
228 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" | 228 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" |
229 | " %s\n", config_item_name(item)); | 229 | " %s\n", config_item_name(item)); |
230 | 230 | ||
231 | tf_group = &tf->tf_group; | 231 | tf_group = &tf->tf_group; |
232 | for (i = 0; tf_group->default_groups[i]; i++) { | 232 | for (i = 0; tf_group->default_groups[i]; i++) { |
233 | df_item = &tf_group->default_groups[i]->cg_item; | 233 | df_item = &tf_group->default_groups[i]->cg_item; |
234 | tf_group->default_groups[i] = NULL; | 234 | tf_group->default_groups[i] = NULL; |
235 | config_item_put(df_item); | 235 | config_item_put(df_item); |
236 | } | 236 | } |
237 | config_item_put(item); | 237 | config_item_put(item); |
238 | } | 238 | } |
239 | 239 | ||
240 | static struct configfs_group_operations target_core_fabric_group_ops = { | 240 | static struct configfs_group_operations target_core_fabric_group_ops = { |
241 | .make_group = &target_core_register_fabric, | 241 | .make_group = &target_core_register_fabric, |
242 | .drop_item = &target_core_deregister_fabric, | 242 | .drop_item = &target_core_deregister_fabric, |
243 | }; | 243 | }; |
244 | 244 | ||
245 | /* | 245 | /* |
246 | * All item attributes appearing in /sys/kernel/target/ appear here. | 246 | * All item attributes appearing in /sys/kernel/target/ appear here. |
247 | */ | 247 | */ |
248 | static struct configfs_attribute *target_core_fabric_item_attrs[] = { | 248 | static struct configfs_attribute *target_core_fabric_item_attrs[] = { |
249 | &target_core_item_attr_version, | 249 | &target_core_item_attr_version, |
250 | NULL, | 250 | NULL, |
251 | }; | 251 | }; |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/ | 254 | * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/ |
255 | */ | 255 | */ |
256 | static struct config_item_type target_core_fabrics_item = { | 256 | static struct config_item_type target_core_fabrics_item = { |
257 | .ct_item_ops = &target_core_fabric_item_ops, | 257 | .ct_item_ops = &target_core_fabric_item_ops, |
258 | .ct_group_ops = &target_core_fabric_group_ops, | 258 | .ct_group_ops = &target_core_fabric_group_ops, |
259 | .ct_attrs = target_core_fabric_item_attrs, | 259 | .ct_attrs = target_core_fabric_item_attrs, |
260 | .ct_owner = THIS_MODULE, | 260 | .ct_owner = THIS_MODULE, |
261 | }; | 261 | }; |
262 | 262 | ||
263 | static struct configfs_subsystem target_core_fabrics = { | 263 | static struct configfs_subsystem target_core_fabrics = { |
264 | .su_group = { | 264 | .su_group = { |
265 | .cg_item = { | 265 | .cg_item = { |
266 | .ci_namebuf = "target", | 266 | .ci_namebuf = "target", |
267 | .ci_type = &target_core_fabrics_item, | 267 | .ci_type = &target_core_fabrics_item, |
268 | }, | 268 | }, |
269 | }, | 269 | }, |
270 | }; | 270 | }; |
271 | 271 | ||
272 | static struct configfs_subsystem *target_core_subsystem[] = { | 272 | static struct configfs_subsystem *target_core_subsystem[] = { |
273 | &target_core_fabrics, | 273 | &target_core_fabrics, |
274 | NULL, | 274 | NULL, |
275 | }; | 275 | }; |
276 | 276 | ||
277 | /*############################################################################## | 277 | /*############################################################################## |
278 | // Start functions called by external Target Fabrics Modules | 278 | // Start functions called by external Target Fabrics Modules |
279 | //############################################################################*/ | 279 | //############################################################################*/ |
280 | 280 | ||
281 | /* | 281 | /* |
282 | * First function called by fabric modules to: | 282 | * First function called by fabric modules to: |
283 | * | 283 | * |
284 | * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer. | 284 | * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer. |
285 | * 2) Add struct target_fabric_configfs to g_tf_list | 285 | * 2) Add struct target_fabric_configfs to g_tf_list |
286 | * 3) Return struct target_fabric_configfs to fabric module to be passed | 286 | * 3) Return struct target_fabric_configfs to fabric module to be passed |
287 | * into target_fabric_configfs_register(). | 287 | * into target_fabric_configfs_register(). |
288 | */ | 288 | */ |
289 | struct target_fabric_configfs *target_fabric_configfs_init( | 289 | struct target_fabric_configfs *target_fabric_configfs_init( |
290 | struct module *fabric_mod, | 290 | struct module *fabric_mod, |
291 | const char *name) | 291 | const char *name) |
292 | { | 292 | { |
293 | struct target_fabric_configfs *tf; | 293 | struct target_fabric_configfs *tf; |
294 | 294 | ||
295 | if (!(name)) { | 295 | if (!(name)) { |
296 | pr_err("Unable to locate passed fabric name\n"); | 296 | pr_err("Unable to locate passed fabric name\n"); |
297 | return ERR_PTR(-EINVAL); | 297 | return ERR_PTR(-EINVAL); |
298 | } | 298 | } |
299 | if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) { | 299 | if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) { |
300 | pr_err("Passed name: %s exceeds TARGET_FABRIC" | 300 | pr_err("Passed name: %s exceeds TARGET_FABRIC" |
301 | "_NAME_SIZE\n", name); | 301 | "_NAME_SIZE\n", name); |
302 | return ERR_PTR(-EINVAL); | 302 | return ERR_PTR(-EINVAL); |
303 | } | 303 | } |
304 | 304 | ||
305 | tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); | 305 | tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); |
306 | if (!tf) | 306 | if (!tf) |
307 | return ERR_PTR(-ENOMEM); | 307 | return ERR_PTR(-ENOMEM); |
308 | 308 | ||
309 | INIT_LIST_HEAD(&tf->tf_list); | 309 | INIT_LIST_HEAD(&tf->tf_list); |
310 | atomic_set(&tf->tf_access_cnt, 0); | 310 | atomic_set(&tf->tf_access_cnt, 0); |
311 | /* | 311 | /* |
312 | * Setup the default generic struct config_item_type's (cits) in | 312 | * Setup the default generic struct config_item_type's (cits) in |
313 | * struct target_fabric_configfs->tf_cit_tmpl | 313 | * struct target_fabric_configfs->tf_cit_tmpl |
314 | */ | 314 | */ |
315 | tf->tf_module = fabric_mod; | 315 | tf->tf_module = fabric_mod; |
316 | target_fabric_setup_cits(tf); | 316 | target_fabric_setup_cits(tf); |
317 | 317 | ||
318 | tf->tf_subsys = target_core_subsystem[0]; | 318 | tf->tf_subsys = target_core_subsystem[0]; |
319 | snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name); | 319 | snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name); |
320 | 320 | ||
321 | mutex_lock(&g_tf_lock); | 321 | mutex_lock(&g_tf_lock); |
322 | list_add_tail(&tf->tf_list, &g_tf_list); | 322 | list_add_tail(&tf->tf_list, &g_tf_list); |
323 | mutex_unlock(&g_tf_lock); | 323 | mutex_unlock(&g_tf_lock); |
324 | 324 | ||
325 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>" | 325 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>" |
326 | ">>>>>>>>>>>>>>\n"); | 326 | ">>>>>>>>>>>>>>\n"); |
327 | pr_debug("Initialized struct target_fabric_configfs: %p for" | 327 | pr_debug("Initialized struct target_fabric_configfs: %p for" |
328 | " %s\n", tf, tf->tf_name); | 328 | " %s\n", tf, tf->tf_name); |
329 | return tf; | 329 | return tf; |
330 | } | 330 | } |
331 | EXPORT_SYMBOL(target_fabric_configfs_init); | 331 | EXPORT_SYMBOL(target_fabric_configfs_init); |
332 | 332 | ||
333 | /* | 333 | /* |
334 | * Called by fabric plugins after FAILED target_fabric_configfs_register() call. | 334 | * Called by fabric plugins after FAILED target_fabric_configfs_register() call. |
335 | */ | 335 | */ |
336 | void target_fabric_configfs_free( | 336 | void target_fabric_configfs_free( |
337 | struct target_fabric_configfs *tf) | 337 | struct target_fabric_configfs *tf) |
338 | { | 338 | { |
339 | mutex_lock(&g_tf_lock); | 339 | mutex_lock(&g_tf_lock); |
340 | list_del(&tf->tf_list); | 340 | list_del(&tf->tf_list); |
341 | mutex_unlock(&g_tf_lock); | 341 | mutex_unlock(&g_tf_lock); |
342 | 342 | ||
343 | kfree(tf); | 343 | kfree(tf); |
344 | } | 344 | } |
345 | EXPORT_SYMBOL(target_fabric_configfs_free); | 345 | EXPORT_SYMBOL(target_fabric_configfs_free); |
346 | 346 | ||
347 | /* | 347 | /* |
348 | * Perform a sanity check of the passed tf->tf_ops before completing | 348 | * Perform a sanity check of the passed tf->tf_ops before completing |
349 | * TCM fabric module registration. | 349 | * TCM fabric module registration. |
350 | */ | 350 | */ |
351 | static int target_fabric_tf_ops_check( | 351 | static int target_fabric_tf_ops_check( |
352 | struct target_fabric_configfs *tf) | 352 | struct target_fabric_configfs *tf) |
353 | { | 353 | { |
354 | struct target_core_fabric_ops *tfo = &tf->tf_ops; | 354 | struct target_core_fabric_ops *tfo = &tf->tf_ops; |
355 | 355 | ||
356 | if (!tfo->get_fabric_name) { | 356 | if (!tfo->get_fabric_name) { |
357 | pr_err("Missing tfo->get_fabric_name()\n"); | 357 | pr_err("Missing tfo->get_fabric_name()\n"); |
358 | return -EINVAL; | 358 | return -EINVAL; |
359 | } | 359 | } |
360 | if (!tfo->get_fabric_proto_ident) { | 360 | if (!tfo->get_fabric_proto_ident) { |
361 | pr_err("Missing tfo->get_fabric_proto_ident()\n"); | 361 | pr_err("Missing tfo->get_fabric_proto_ident()\n"); |
362 | return -EINVAL; | 362 | return -EINVAL; |
363 | } | 363 | } |
364 | if (!tfo->tpg_get_wwn) { | 364 | if (!tfo->tpg_get_wwn) { |
365 | pr_err("Missing tfo->tpg_get_wwn()\n"); | 365 | pr_err("Missing tfo->tpg_get_wwn()\n"); |
366 | return -EINVAL; | 366 | return -EINVAL; |
367 | } | 367 | } |
368 | if (!tfo->tpg_get_tag) { | 368 | if (!tfo->tpg_get_tag) { |
369 | pr_err("Missing tfo->tpg_get_tag()\n"); | 369 | pr_err("Missing tfo->tpg_get_tag()\n"); |
370 | return -EINVAL; | 370 | return -EINVAL; |
371 | } | 371 | } |
372 | if (!tfo->tpg_get_default_depth) { | 372 | if (!tfo->tpg_get_default_depth) { |
373 | pr_err("Missing tfo->tpg_get_default_depth()\n"); | 373 | pr_err("Missing tfo->tpg_get_default_depth()\n"); |
374 | return -EINVAL; | 374 | return -EINVAL; |
375 | } | 375 | } |
376 | if (!tfo->tpg_get_pr_transport_id) { | 376 | if (!tfo->tpg_get_pr_transport_id) { |
377 | pr_err("Missing tfo->tpg_get_pr_transport_id()\n"); | 377 | pr_err("Missing tfo->tpg_get_pr_transport_id()\n"); |
378 | return -EINVAL; | 378 | return -EINVAL; |
379 | } | 379 | } |
380 | if (!tfo->tpg_get_pr_transport_id_len) { | 380 | if (!tfo->tpg_get_pr_transport_id_len) { |
381 | pr_err("Missing tfo->tpg_get_pr_transport_id_len()\n"); | 381 | pr_err("Missing tfo->tpg_get_pr_transport_id_len()\n"); |
382 | return -EINVAL; | 382 | return -EINVAL; |
383 | } | 383 | } |
384 | if (!tfo->tpg_check_demo_mode) { | 384 | if (!tfo->tpg_check_demo_mode) { |
385 | pr_err("Missing tfo->tpg_check_demo_mode()\n"); | 385 | pr_err("Missing tfo->tpg_check_demo_mode()\n"); |
386 | return -EINVAL; | 386 | return -EINVAL; |
387 | } | 387 | } |
388 | if (!tfo->tpg_check_demo_mode_cache) { | 388 | if (!tfo->tpg_check_demo_mode_cache) { |
389 | pr_err("Missing tfo->tpg_check_demo_mode_cache()\n"); | 389 | pr_err("Missing tfo->tpg_check_demo_mode_cache()\n"); |
390 | return -EINVAL; | 390 | return -EINVAL; |
391 | } | 391 | } |
392 | if (!tfo->tpg_check_demo_mode_write_protect) { | 392 | if (!tfo->tpg_check_demo_mode_write_protect) { |
393 | pr_err("Missing tfo->tpg_check_demo_mode_write_protect()\n"); | 393 | pr_err("Missing tfo->tpg_check_demo_mode_write_protect()\n"); |
394 | return -EINVAL; | 394 | return -EINVAL; |
395 | } | 395 | } |
396 | if (!tfo->tpg_check_prod_mode_write_protect) { | 396 | if (!tfo->tpg_check_prod_mode_write_protect) { |
397 | pr_err("Missing tfo->tpg_check_prod_mode_write_protect()\n"); | 397 | pr_err("Missing tfo->tpg_check_prod_mode_write_protect()\n"); |
398 | return -EINVAL; | 398 | return -EINVAL; |
399 | } | 399 | } |
400 | if (!tfo->tpg_alloc_fabric_acl) { | 400 | if (!tfo->tpg_alloc_fabric_acl) { |
401 | pr_err("Missing tfo->tpg_alloc_fabric_acl()\n"); | 401 | pr_err("Missing tfo->tpg_alloc_fabric_acl()\n"); |
402 | return -EINVAL; | 402 | return -EINVAL; |
403 | } | 403 | } |
404 | if (!tfo->tpg_release_fabric_acl) { | 404 | if (!tfo->tpg_release_fabric_acl) { |
405 | pr_err("Missing tfo->tpg_release_fabric_acl()\n"); | 405 | pr_err("Missing tfo->tpg_release_fabric_acl()\n"); |
406 | return -EINVAL; | 406 | return -EINVAL; |
407 | } | 407 | } |
408 | if (!tfo->tpg_get_inst_index) { | 408 | if (!tfo->tpg_get_inst_index) { |
409 | pr_err("Missing tfo->tpg_get_inst_index()\n"); | 409 | pr_err("Missing tfo->tpg_get_inst_index()\n"); |
410 | return -EINVAL; | 410 | return -EINVAL; |
411 | } | 411 | } |
412 | if (!tfo->release_cmd) { | 412 | if (!tfo->release_cmd) { |
413 | pr_err("Missing tfo->release_cmd()\n"); | 413 | pr_err("Missing tfo->release_cmd()\n"); |
414 | return -EINVAL; | 414 | return -EINVAL; |
415 | } | 415 | } |
416 | if (!tfo->shutdown_session) { | 416 | if (!tfo->shutdown_session) { |
417 | pr_err("Missing tfo->shutdown_session()\n"); | 417 | pr_err("Missing tfo->shutdown_session()\n"); |
418 | return -EINVAL; | 418 | return -EINVAL; |
419 | } | 419 | } |
420 | if (!tfo->close_session) { | 420 | if (!tfo->close_session) { |
421 | pr_err("Missing tfo->close_session()\n"); | 421 | pr_err("Missing tfo->close_session()\n"); |
422 | return -EINVAL; | 422 | return -EINVAL; |
423 | } | 423 | } |
424 | if (!tfo->stop_session) { | 424 | if (!tfo->stop_session) { |
425 | pr_err("Missing tfo->stop_session()\n"); | 425 | pr_err("Missing tfo->stop_session()\n"); |
426 | return -EINVAL; | 426 | return -EINVAL; |
427 | } | 427 | } |
428 | if (!tfo->fall_back_to_erl0) { | 428 | if (!tfo->fall_back_to_erl0) { |
429 | pr_err("Missing tfo->fall_back_to_erl0()\n"); | 429 | pr_err("Missing tfo->fall_back_to_erl0()\n"); |
430 | return -EINVAL; | 430 | return -EINVAL; |
431 | } | 431 | } |
432 | if (!tfo->sess_logged_in) { | 432 | if (!tfo->sess_logged_in) { |
433 | pr_err("Missing tfo->sess_logged_in()\n"); | 433 | pr_err("Missing tfo->sess_logged_in()\n"); |
434 | return -EINVAL; | 434 | return -EINVAL; |
435 | } | 435 | } |
436 | if (!tfo->sess_get_index) { | 436 | if (!tfo->sess_get_index) { |
437 | pr_err("Missing tfo->sess_get_index()\n"); | 437 | pr_err("Missing tfo->sess_get_index()\n"); |
438 | return -EINVAL; | 438 | return -EINVAL; |
439 | } | 439 | } |
440 | if (!tfo->write_pending) { | 440 | if (!tfo->write_pending) { |
441 | pr_err("Missing tfo->write_pending()\n"); | 441 | pr_err("Missing tfo->write_pending()\n"); |
442 | return -EINVAL; | 442 | return -EINVAL; |
443 | } | 443 | } |
444 | if (!tfo->write_pending_status) { | 444 | if (!tfo->write_pending_status) { |
445 | pr_err("Missing tfo->write_pending_status()\n"); | 445 | pr_err("Missing tfo->write_pending_status()\n"); |
446 | return -EINVAL; | 446 | return -EINVAL; |
447 | } | 447 | } |
448 | if (!tfo->set_default_node_attributes) { | 448 | if (!tfo->set_default_node_attributes) { |
449 | pr_err("Missing tfo->set_default_node_attributes()\n"); | 449 | pr_err("Missing tfo->set_default_node_attributes()\n"); |
450 | return -EINVAL; | 450 | return -EINVAL; |
451 | } | 451 | } |
452 | if (!tfo->get_task_tag) { | 452 | if (!tfo->get_task_tag) { |
453 | pr_err("Missing tfo->get_task_tag()\n"); | 453 | pr_err("Missing tfo->get_task_tag()\n"); |
454 | return -EINVAL; | 454 | return -EINVAL; |
455 | } | 455 | } |
456 | if (!tfo->get_cmd_state) { | 456 | if (!tfo->get_cmd_state) { |
457 | pr_err("Missing tfo->get_cmd_state()\n"); | 457 | pr_err("Missing tfo->get_cmd_state()\n"); |
458 | return -EINVAL; | 458 | return -EINVAL; |
459 | } | 459 | } |
460 | if (!tfo->queue_data_in) { | 460 | if (!tfo->queue_data_in) { |
461 | pr_err("Missing tfo->queue_data_in()\n"); | 461 | pr_err("Missing tfo->queue_data_in()\n"); |
462 | return -EINVAL; | 462 | return -EINVAL; |
463 | } | 463 | } |
464 | if (!tfo->queue_status) { | 464 | if (!tfo->queue_status) { |
465 | pr_err("Missing tfo->queue_status()\n"); | 465 | pr_err("Missing tfo->queue_status()\n"); |
466 | return -EINVAL; | 466 | return -EINVAL; |
467 | } | 467 | } |
468 | if (!tfo->queue_tm_rsp) { | 468 | if (!tfo->queue_tm_rsp) { |
469 | pr_err("Missing tfo->queue_tm_rsp()\n"); | 469 | pr_err("Missing tfo->queue_tm_rsp()\n"); |
470 | return -EINVAL; | 470 | return -EINVAL; |
471 | } | 471 | } |
472 | if (!tfo->set_fabric_sense_len) { | 472 | if (!tfo->set_fabric_sense_len) { |
473 | pr_err("Missing tfo->set_fabric_sense_len()\n"); | 473 | pr_err("Missing tfo->set_fabric_sense_len()\n"); |
474 | return -EINVAL; | 474 | return -EINVAL; |
475 | } | 475 | } |
476 | if (!tfo->get_fabric_sense_len) { | 476 | if (!tfo->get_fabric_sense_len) { |
477 | pr_err("Missing tfo->get_fabric_sense_len()\n"); | 477 | pr_err("Missing tfo->get_fabric_sense_len()\n"); |
478 | return -EINVAL; | 478 | return -EINVAL; |
479 | } | 479 | } |
480 | if (!tfo->is_state_remove) { | 480 | if (!tfo->is_state_remove) { |
481 | pr_err("Missing tfo->is_state_remove()\n"); | 481 | pr_err("Missing tfo->is_state_remove()\n"); |
482 | return -EINVAL; | 482 | return -EINVAL; |
483 | } | 483 | } |
484 | /* | 484 | /* |
485 | * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn() | 485 | * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn() |
486 | * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in | 486 | * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in |
487 | * target_core_fabric_configfs.c WWN+TPG group context code. | 487 | * target_core_fabric_configfs.c WWN+TPG group context code. |
488 | */ | 488 | */ |
489 | if (!tfo->fabric_make_wwn) { | 489 | if (!tfo->fabric_make_wwn) { |
490 | pr_err("Missing tfo->fabric_make_wwn()\n"); | 490 | pr_err("Missing tfo->fabric_make_wwn()\n"); |
491 | return -EINVAL; | 491 | return -EINVAL; |
492 | } | 492 | } |
493 | if (!tfo->fabric_drop_wwn) { | 493 | if (!tfo->fabric_drop_wwn) { |
494 | pr_err("Missing tfo->fabric_drop_wwn()\n"); | 494 | pr_err("Missing tfo->fabric_drop_wwn()\n"); |
495 | return -EINVAL; | 495 | return -EINVAL; |
496 | } | 496 | } |
497 | if (!tfo->fabric_make_tpg) { | 497 | if (!tfo->fabric_make_tpg) { |
498 | pr_err("Missing tfo->fabric_make_tpg()\n"); | 498 | pr_err("Missing tfo->fabric_make_tpg()\n"); |
499 | return -EINVAL; | 499 | return -EINVAL; |
500 | } | 500 | } |
501 | if (!tfo->fabric_drop_tpg) { | 501 | if (!tfo->fabric_drop_tpg) { |
502 | pr_err("Missing tfo->fabric_drop_tpg()\n"); | 502 | pr_err("Missing tfo->fabric_drop_tpg()\n"); |
503 | return -EINVAL; | 503 | return -EINVAL; |
504 | } | 504 | } |
505 | 505 | ||
506 | return 0; | 506 | return 0; |
507 | } | 507 | } |
508 | 508 | ||
509 | /* | 509 | /* |
510 | * Called 2nd from fabric module with returned parameter of | 510 | * Called 2nd from fabric module with returned parameter of |
511 | * struct target_fabric_configfs * from target_fabric_configfs_init(). | 511 | * struct target_fabric_configfs * from target_fabric_configfs_init(). |
512 | * | 512 | * |
513 | * Upon a successful registration, the new fabric's struct config_item is | 513 | * Upon a successful registration, the new fabric's struct config_item is |
514 | * return. Also, a pointer to this struct is set in the passed | 514 | * return. Also, a pointer to this struct is set in the passed |
515 | * struct target_fabric_configfs. | 515 | * struct target_fabric_configfs. |
516 | */ | 516 | */ |
517 | int target_fabric_configfs_register( | 517 | int target_fabric_configfs_register( |
518 | struct target_fabric_configfs *tf) | 518 | struct target_fabric_configfs *tf) |
519 | { | 519 | { |
520 | int ret; | 520 | int ret; |
521 | 521 | ||
522 | if (!tf) { | 522 | if (!tf) { |
523 | pr_err("Unable to locate target_fabric_configfs" | 523 | pr_err("Unable to locate target_fabric_configfs" |
524 | " pointer\n"); | 524 | " pointer\n"); |
525 | return -EINVAL; | 525 | return -EINVAL; |
526 | } | 526 | } |
527 | if (!tf->tf_subsys) { | 527 | if (!tf->tf_subsys) { |
528 | pr_err("Unable to target struct config_subsystem" | 528 | pr_err("Unable to target struct config_subsystem" |
529 | " pointer\n"); | 529 | " pointer\n"); |
530 | return -EINVAL; | 530 | return -EINVAL; |
531 | } | 531 | } |
532 | ret = target_fabric_tf_ops_check(tf); | 532 | ret = target_fabric_tf_ops_check(tf); |
533 | if (ret < 0) | 533 | if (ret < 0) |
534 | return ret; | 534 | return ret; |
535 | 535 | ||
536 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>" | 536 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>" |
537 | ">>>>>>>>>>\n"); | 537 | ">>>>>>>>>>\n"); |
538 | return 0; | 538 | return 0; |
539 | } | 539 | } |
540 | EXPORT_SYMBOL(target_fabric_configfs_register); | 540 | EXPORT_SYMBOL(target_fabric_configfs_register); |
541 | 541 | ||
542 | void target_fabric_configfs_deregister( | 542 | void target_fabric_configfs_deregister( |
543 | struct target_fabric_configfs *tf) | 543 | struct target_fabric_configfs *tf) |
544 | { | 544 | { |
545 | struct configfs_subsystem *su; | 545 | struct configfs_subsystem *su; |
546 | 546 | ||
547 | if (!tf) { | 547 | if (!tf) { |
548 | pr_err("Unable to locate passed target_fabric_" | 548 | pr_err("Unable to locate passed target_fabric_" |
549 | "configfs\n"); | 549 | "configfs\n"); |
550 | return; | 550 | return; |
551 | } | 551 | } |
552 | su = tf->tf_subsys; | 552 | su = tf->tf_subsys; |
553 | if (!su) { | 553 | if (!su) { |
554 | pr_err("Unable to locate passed tf->tf_subsys" | 554 | pr_err("Unable to locate passed tf->tf_subsys" |
555 | " pointer\n"); | 555 | " pointer\n"); |
556 | return; | 556 | return; |
557 | } | 557 | } |
558 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>" | 558 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>" |
559 | ">>>>>>>>>>>>\n"); | 559 | ">>>>>>>>>>>>\n"); |
560 | mutex_lock(&g_tf_lock); | 560 | mutex_lock(&g_tf_lock); |
561 | if (atomic_read(&tf->tf_access_cnt)) { | 561 | if (atomic_read(&tf->tf_access_cnt)) { |
562 | mutex_unlock(&g_tf_lock); | 562 | mutex_unlock(&g_tf_lock); |
563 | pr_err("Non zero tf->tf_access_cnt for fabric %s\n", | 563 | pr_err("Non zero tf->tf_access_cnt for fabric %s\n", |
564 | tf->tf_name); | 564 | tf->tf_name); |
565 | BUG(); | 565 | BUG(); |
566 | } | 566 | } |
567 | list_del(&tf->tf_list); | 567 | list_del(&tf->tf_list); |
568 | mutex_unlock(&g_tf_lock); | 568 | mutex_unlock(&g_tf_lock); |
569 | 569 | ||
570 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:" | 570 | pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:" |
571 | " %s\n", tf->tf_name); | 571 | " %s\n", tf->tf_name); |
572 | tf->tf_module = NULL; | 572 | tf->tf_module = NULL; |
573 | tf->tf_subsys = NULL; | 573 | tf->tf_subsys = NULL; |
574 | kfree(tf); | 574 | kfree(tf); |
575 | 575 | ||
576 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>" | 576 | pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>" |
577 | ">>>>>\n"); | 577 | ">>>>>\n"); |
578 | } | 578 | } |
579 | EXPORT_SYMBOL(target_fabric_configfs_deregister); | 579 | EXPORT_SYMBOL(target_fabric_configfs_deregister); |
580 | 580 | ||
581 | /*############################################################################## | 581 | /*############################################################################## |
582 | // Stop functions called by external Target Fabrics Modules | 582 | // Stop functions called by external Target Fabrics Modules |
583 | //############################################################################*/ | 583 | //############################################################################*/ |
584 | 584 | ||
585 | /* Start functions for struct config_item_type target_core_dev_attrib_cit */ | 585 | /* Start functions for struct config_item_type target_core_dev_attrib_cit */ |
586 | 586 | ||
587 | #define DEF_DEV_ATTRIB_SHOW(_name) \ | 587 | #define DEF_DEV_ATTRIB_SHOW(_name) \ |
588 | static ssize_t target_core_dev_show_attr_##_name( \ | 588 | static ssize_t target_core_dev_show_attr_##_name( \ |
589 | struct se_dev_attrib *da, \ | 589 | struct se_dev_attrib *da, \ |
590 | char *page) \ | 590 | char *page) \ |
591 | { \ | 591 | { \ |
592 | struct se_device *dev; \ | 592 | struct se_device *dev; \ |
593 | struct se_subsystem_dev *se_dev = da->da_sub_dev; \ | 593 | struct se_subsystem_dev *se_dev = da->da_sub_dev; \ |
594 | ssize_t rb; \ | 594 | ssize_t rb; \ |
595 | \ | 595 | \ |
596 | spin_lock(&se_dev->se_dev_lock); \ | 596 | spin_lock(&se_dev->se_dev_lock); \ |
597 | dev = se_dev->se_dev_ptr; \ | 597 | dev = se_dev->se_dev_ptr; \ |
598 | if (!dev) { \ | 598 | if (!dev) { \ |
599 | spin_unlock(&se_dev->se_dev_lock); \ | 599 | spin_unlock(&se_dev->se_dev_lock); \ |
600 | return -ENODEV; \ | 600 | return -ENODEV; \ |
601 | } \ | 601 | } \ |
602 | rb = snprintf(page, PAGE_SIZE, "%u\n", \ | 602 | rb = snprintf(page, PAGE_SIZE, "%u\n", \ |
603 | (u32)dev->se_sub_dev->se_dev_attrib._name); \ | 603 | (u32)dev->se_sub_dev->se_dev_attrib._name); \ |
604 | spin_unlock(&se_dev->se_dev_lock); \ | 604 | spin_unlock(&se_dev->se_dev_lock); \ |
605 | \ | 605 | \ |
606 | return rb; \ | 606 | return rb; \ |
607 | } | 607 | } |
608 | 608 | ||
609 | #define DEF_DEV_ATTRIB_STORE(_name) \ | 609 | #define DEF_DEV_ATTRIB_STORE(_name) \ |
610 | static ssize_t target_core_dev_store_attr_##_name( \ | 610 | static ssize_t target_core_dev_store_attr_##_name( \ |
611 | struct se_dev_attrib *da, \ | 611 | struct se_dev_attrib *da, \ |
612 | const char *page, \ | 612 | const char *page, \ |
613 | size_t count) \ | 613 | size_t count) \ |
614 | { \ | 614 | { \ |
615 | struct se_device *dev; \ | 615 | struct se_device *dev; \ |
616 | struct se_subsystem_dev *se_dev = da->da_sub_dev; \ | 616 | struct se_subsystem_dev *se_dev = da->da_sub_dev; \ |
617 | unsigned long val; \ | 617 | unsigned long val; \ |
618 | int ret; \ | 618 | int ret; \ |
619 | \ | 619 | \ |
620 | spin_lock(&se_dev->se_dev_lock); \ | 620 | spin_lock(&se_dev->se_dev_lock); \ |
621 | dev = se_dev->se_dev_ptr; \ | 621 | dev = se_dev->se_dev_ptr; \ |
622 | if (!dev) { \ | 622 | if (!dev) { \ |
623 | spin_unlock(&se_dev->se_dev_lock); \ | 623 | spin_unlock(&se_dev->se_dev_lock); \ |
624 | return -ENODEV; \ | 624 | return -ENODEV; \ |
625 | } \ | 625 | } \ |
626 | ret = strict_strtoul(page, 0, &val); \ | 626 | ret = strict_strtoul(page, 0, &val); \ |
627 | if (ret < 0) { \ | 627 | if (ret < 0) { \ |
628 | spin_unlock(&se_dev->se_dev_lock); \ | 628 | spin_unlock(&se_dev->se_dev_lock); \ |
629 | pr_err("strict_strtoul() failed with" \ | 629 | pr_err("strict_strtoul() failed with" \ |
630 | " ret: %d\n", ret); \ | 630 | " ret: %d\n", ret); \ |
631 | return -EINVAL; \ | 631 | return -EINVAL; \ |
632 | } \ | 632 | } \ |
633 | ret = se_dev_set_##_name(dev, (u32)val); \ | 633 | ret = se_dev_set_##_name(dev, (u32)val); \ |
634 | spin_unlock(&se_dev->se_dev_lock); \ | 634 | spin_unlock(&se_dev->se_dev_lock); \ |
635 | \ | 635 | \ |
636 | return (!ret) ? count : -EINVAL; \ | 636 | return (!ret) ? count : -EINVAL; \ |
637 | } | 637 | } |
638 | 638 | ||
639 | #define DEF_DEV_ATTRIB(_name) \ | 639 | #define DEF_DEV_ATTRIB(_name) \ |
640 | DEF_DEV_ATTRIB_SHOW(_name); \ | 640 | DEF_DEV_ATTRIB_SHOW(_name); \ |
641 | DEF_DEV_ATTRIB_STORE(_name); | 641 | DEF_DEV_ATTRIB_STORE(_name); |
642 | 642 | ||
643 | #define DEF_DEV_ATTRIB_RO(_name) \ | 643 | #define DEF_DEV_ATTRIB_RO(_name) \ |
644 | DEF_DEV_ATTRIB_SHOW(_name); | 644 | DEF_DEV_ATTRIB_SHOW(_name); |
645 | 645 | ||
646 | CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib); | 646 | CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib); |
647 | #define SE_DEV_ATTR(_name, _mode) \ | 647 | #define SE_DEV_ATTR(_name, _mode) \ |
648 | static struct target_core_dev_attrib_attribute \ | 648 | static struct target_core_dev_attrib_attribute \ |
649 | target_core_dev_attrib_##_name = \ | 649 | target_core_dev_attrib_##_name = \ |
650 | __CONFIGFS_EATTR(_name, _mode, \ | 650 | __CONFIGFS_EATTR(_name, _mode, \ |
651 | target_core_dev_show_attr_##_name, \ | 651 | target_core_dev_show_attr_##_name, \ |
652 | target_core_dev_store_attr_##_name); | 652 | target_core_dev_store_attr_##_name); |
653 | 653 | ||
654 | #define SE_DEV_ATTR_RO(_name); \ | 654 | #define SE_DEV_ATTR_RO(_name); \ |
655 | static struct target_core_dev_attrib_attribute \ | 655 | static struct target_core_dev_attrib_attribute \ |
656 | target_core_dev_attrib_##_name = \ | 656 | target_core_dev_attrib_##_name = \ |
657 | __CONFIGFS_EATTR_RO(_name, \ | 657 | __CONFIGFS_EATTR_RO(_name, \ |
658 | target_core_dev_show_attr_##_name); | 658 | target_core_dev_show_attr_##_name); |
659 | 659 | ||
660 | DEF_DEV_ATTRIB(emulate_dpo); | 660 | DEF_DEV_ATTRIB(emulate_dpo); |
661 | SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR); | 661 | SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR); |
662 | 662 | ||
663 | DEF_DEV_ATTRIB(emulate_fua_write); | 663 | DEF_DEV_ATTRIB(emulate_fua_write); |
664 | SE_DEV_ATTR(emulate_fua_write, S_IRUGO | S_IWUSR); | 664 | SE_DEV_ATTR(emulate_fua_write, S_IRUGO | S_IWUSR); |
665 | 665 | ||
666 | DEF_DEV_ATTRIB(emulate_fua_read); | 666 | DEF_DEV_ATTRIB(emulate_fua_read); |
667 | SE_DEV_ATTR(emulate_fua_read, S_IRUGO | S_IWUSR); | 667 | SE_DEV_ATTR(emulate_fua_read, S_IRUGO | S_IWUSR); |
668 | 668 | ||
669 | DEF_DEV_ATTRIB(emulate_write_cache); | 669 | DEF_DEV_ATTRIB(emulate_write_cache); |
670 | SE_DEV_ATTR(emulate_write_cache, S_IRUGO | S_IWUSR); | 670 | SE_DEV_ATTR(emulate_write_cache, S_IRUGO | S_IWUSR); |
671 | 671 | ||
672 | DEF_DEV_ATTRIB(emulate_ua_intlck_ctrl); | 672 | DEF_DEV_ATTRIB(emulate_ua_intlck_ctrl); |
673 | SE_DEV_ATTR(emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); | 673 | SE_DEV_ATTR(emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); |
674 | 674 | ||
675 | DEF_DEV_ATTRIB(emulate_tas); | 675 | DEF_DEV_ATTRIB(emulate_tas); |
676 | SE_DEV_ATTR(emulate_tas, S_IRUGO | S_IWUSR); | 676 | SE_DEV_ATTR(emulate_tas, S_IRUGO | S_IWUSR); |
677 | 677 | ||
678 | DEF_DEV_ATTRIB(emulate_tpu); | 678 | DEF_DEV_ATTRIB(emulate_tpu); |
679 | SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR); | 679 | SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR); |
680 | 680 | ||
681 | DEF_DEV_ATTRIB(emulate_tpws); | 681 | DEF_DEV_ATTRIB(emulate_tpws); |
682 | SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR); | 682 | SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR); |
683 | 683 | ||
684 | DEF_DEV_ATTRIB(enforce_pr_isids); | 684 | DEF_DEV_ATTRIB(enforce_pr_isids); |
685 | SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR); | 685 | SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR); |
686 | 686 | ||
687 | DEF_DEV_ATTRIB(is_nonrot); | 687 | DEF_DEV_ATTRIB(is_nonrot); |
688 | SE_DEV_ATTR(is_nonrot, S_IRUGO | S_IWUSR); | 688 | SE_DEV_ATTR(is_nonrot, S_IRUGO | S_IWUSR); |
689 | 689 | ||
690 | DEF_DEV_ATTRIB(emulate_rest_reord); | 690 | DEF_DEV_ATTRIB(emulate_rest_reord); |
691 | SE_DEV_ATTR(emulate_rest_reord, S_IRUGO | S_IWUSR); | 691 | SE_DEV_ATTR(emulate_rest_reord, S_IRUGO | S_IWUSR); |
692 | 692 | ||
693 | DEF_DEV_ATTRIB_RO(hw_block_size); | 693 | DEF_DEV_ATTRIB_RO(hw_block_size); |
694 | SE_DEV_ATTR_RO(hw_block_size); | 694 | SE_DEV_ATTR_RO(hw_block_size); |
695 | 695 | ||
696 | DEF_DEV_ATTRIB(block_size); | 696 | DEF_DEV_ATTRIB(block_size); |
697 | SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR); | 697 | SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR); |
698 | 698 | ||
699 | DEF_DEV_ATTRIB_RO(hw_max_sectors); | 699 | DEF_DEV_ATTRIB_RO(hw_max_sectors); |
700 | SE_DEV_ATTR_RO(hw_max_sectors); | 700 | SE_DEV_ATTR_RO(hw_max_sectors); |
701 | 701 | ||
702 | DEF_DEV_ATTRIB(max_sectors); | 702 | DEF_DEV_ATTRIB(max_sectors); |
703 | SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR); | 703 | SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR); |
704 | 704 | ||
705 | DEF_DEV_ATTRIB(optimal_sectors); | 705 | DEF_DEV_ATTRIB(optimal_sectors); |
706 | SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR); | 706 | SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR); |
707 | 707 | ||
708 | DEF_DEV_ATTRIB_RO(hw_queue_depth); | 708 | DEF_DEV_ATTRIB_RO(hw_queue_depth); |
709 | SE_DEV_ATTR_RO(hw_queue_depth); | 709 | SE_DEV_ATTR_RO(hw_queue_depth); |
710 | 710 | ||
711 | DEF_DEV_ATTRIB(queue_depth); | 711 | DEF_DEV_ATTRIB(queue_depth); |
712 | SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR); | 712 | SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR); |
713 | 713 | ||
714 | DEF_DEV_ATTRIB(max_unmap_lba_count); | 714 | DEF_DEV_ATTRIB(max_unmap_lba_count); |
715 | SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR); | 715 | SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR); |
716 | 716 | ||
717 | DEF_DEV_ATTRIB(max_unmap_block_desc_count); | 717 | DEF_DEV_ATTRIB(max_unmap_block_desc_count); |
718 | SE_DEV_ATTR(max_unmap_block_desc_count, S_IRUGO | S_IWUSR); | 718 | SE_DEV_ATTR(max_unmap_block_desc_count, S_IRUGO | S_IWUSR); |
719 | 719 | ||
720 | DEF_DEV_ATTRIB(unmap_granularity); | 720 | DEF_DEV_ATTRIB(unmap_granularity); |
721 | SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR); | 721 | SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR); |
722 | 722 | ||
723 | DEF_DEV_ATTRIB(unmap_granularity_alignment); | 723 | DEF_DEV_ATTRIB(unmap_granularity_alignment); |
724 | SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR); | 724 | SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR); |
725 | 725 | ||
726 | CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); | 726 | CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); |
727 | 727 | ||
728 | static struct configfs_attribute *target_core_dev_attrib_attrs[] = { | 728 | static struct configfs_attribute *target_core_dev_attrib_attrs[] = { |
729 | &target_core_dev_attrib_emulate_dpo.attr, | 729 | &target_core_dev_attrib_emulate_dpo.attr, |
730 | &target_core_dev_attrib_emulate_fua_write.attr, | 730 | &target_core_dev_attrib_emulate_fua_write.attr, |
731 | &target_core_dev_attrib_emulate_fua_read.attr, | 731 | &target_core_dev_attrib_emulate_fua_read.attr, |
732 | &target_core_dev_attrib_emulate_write_cache.attr, | 732 | &target_core_dev_attrib_emulate_write_cache.attr, |
733 | &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr, | 733 | &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr, |
734 | &target_core_dev_attrib_emulate_tas.attr, | 734 | &target_core_dev_attrib_emulate_tas.attr, |
735 | &target_core_dev_attrib_emulate_tpu.attr, | 735 | &target_core_dev_attrib_emulate_tpu.attr, |
736 | &target_core_dev_attrib_emulate_tpws.attr, | 736 | &target_core_dev_attrib_emulate_tpws.attr, |
737 | &target_core_dev_attrib_enforce_pr_isids.attr, | 737 | &target_core_dev_attrib_enforce_pr_isids.attr, |
738 | &target_core_dev_attrib_is_nonrot.attr, | 738 | &target_core_dev_attrib_is_nonrot.attr, |
739 | &target_core_dev_attrib_emulate_rest_reord.attr, | 739 | &target_core_dev_attrib_emulate_rest_reord.attr, |
740 | &target_core_dev_attrib_hw_block_size.attr, | 740 | &target_core_dev_attrib_hw_block_size.attr, |
741 | &target_core_dev_attrib_block_size.attr, | 741 | &target_core_dev_attrib_block_size.attr, |
742 | &target_core_dev_attrib_hw_max_sectors.attr, | 742 | &target_core_dev_attrib_hw_max_sectors.attr, |
743 | &target_core_dev_attrib_max_sectors.attr, | 743 | &target_core_dev_attrib_max_sectors.attr, |
744 | &target_core_dev_attrib_optimal_sectors.attr, | 744 | &target_core_dev_attrib_optimal_sectors.attr, |
745 | &target_core_dev_attrib_hw_queue_depth.attr, | 745 | &target_core_dev_attrib_hw_queue_depth.attr, |
746 | &target_core_dev_attrib_queue_depth.attr, | 746 | &target_core_dev_attrib_queue_depth.attr, |
747 | &target_core_dev_attrib_max_unmap_lba_count.attr, | 747 | &target_core_dev_attrib_max_unmap_lba_count.attr, |
748 | &target_core_dev_attrib_max_unmap_block_desc_count.attr, | 748 | &target_core_dev_attrib_max_unmap_block_desc_count.attr, |
749 | &target_core_dev_attrib_unmap_granularity.attr, | 749 | &target_core_dev_attrib_unmap_granularity.attr, |
750 | &target_core_dev_attrib_unmap_granularity_alignment.attr, | 750 | &target_core_dev_attrib_unmap_granularity_alignment.attr, |
751 | NULL, | 751 | NULL, |
752 | }; | 752 | }; |
753 | 753 | ||
754 | static struct configfs_item_operations target_core_dev_attrib_ops = { | 754 | static struct configfs_item_operations target_core_dev_attrib_ops = { |
755 | .show_attribute = target_core_dev_attrib_attr_show, | 755 | .show_attribute = target_core_dev_attrib_attr_show, |
756 | .store_attribute = target_core_dev_attrib_attr_store, | 756 | .store_attribute = target_core_dev_attrib_attr_store, |
757 | }; | 757 | }; |
758 | 758 | ||
759 | static struct config_item_type target_core_dev_attrib_cit = { | 759 | static struct config_item_type target_core_dev_attrib_cit = { |
760 | .ct_item_ops = &target_core_dev_attrib_ops, | 760 | .ct_item_ops = &target_core_dev_attrib_ops, |
761 | .ct_attrs = target_core_dev_attrib_attrs, | 761 | .ct_attrs = target_core_dev_attrib_attrs, |
762 | .ct_owner = THIS_MODULE, | 762 | .ct_owner = THIS_MODULE, |
763 | }; | 763 | }; |
764 | 764 | ||
765 | /* End functions for struct config_item_type target_core_dev_attrib_cit */ | 765 | /* End functions for struct config_item_type target_core_dev_attrib_cit */ |
766 | 766 | ||
767 | /* Start functions for struct config_item_type target_core_dev_wwn_cit */ | 767 | /* Start functions for struct config_item_type target_core_dev_wwn_cit */ |
768 | 768 | ||
769 | CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn); | 769 | CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn); |
770 | #define SE_DEV_WWN_ATTR(_name, _mode) \ | 770 | #define SE_DEV_WWN_ATTR(_name, _mode) \ |
771 | static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \ | 771 | static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \ |
772 | __CONFIGFS_EATTR(_name, _mode, \ | 772 | __CONFIGFS_EATTR(_name, _mode, \ |
773 | target_core_dev_wwn_show_attr_##_name, \ | 773 | target_core_dev_wwn_show_attr_##_name, \ |
774 | target_core_dev_wwn_store_attr_##_name); | 774 | target_core_dev_wwn_store_attr_##_name); |
775 | 775 | ||
776 | #define SE_DEV_WWN_ATTR_RO(_name); \ | 776 | #define SE_DEV_WWN_ATTR_RO(_name); \ |
777 | do { \ | 777 | do { \ |
778 | static struct target_core_dev_wwn_attribute \ | 778 | static struct target_core_dev_wwn_attribute \ |
779 | target_core_dev_wwn_##_name = \ | 779 | target_core_dev_wwn_##_name = \ |
780 | __CONFIGFS_EATTR_RO(_name, \ | 780 | __CONFIGFS_EATTR_RO(_name, \ |
781 | target_core_dev_wwn_show_attr_##_name); \ | 781 | target_core_dev_wwn_show_attr_##_name); \ |
782 | } while (0); | 782 | } while (0); |
783 | 783 | ||
784 | /* | 784 | /* |
785 | * VPD page 0x80 Unit serial | 785 | * VPD page 0x80 Unit serial |
786 | */ | 786 | */ |
787 | static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial( | 787 | static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial( |
788 | struct t10_wwn *t10_wwn, | 788 | struct t10_wwn *t10_wwn, |
789 | char *page) | 789 | char *page) |
790 | { | 790 | { |
791 | struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; | 791 | struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; |
792 | struct se_device *dev; | 792 | struct se_device *dev; |
793 | 793 | ||
794 | dev = se_dev->se_dev_ptr; | 794 | dev = se_dev->se_dev_ptr; |
795 | if (!dev) | 795 | if (!dev) |
796 | return -ENODEV; | 796 | return -ENODEV; |
797 | 797 | ||
798 | return sprintf(page, "T10 VPD Unit Serial Number: %s\n", | 798 | return sprintf(page, "T10 VPD Unit Serial Number: %s\n", |
799 | &t10_wwn->unit_serial[0]); | 799 | &t10_wwn->unit_serial[0]); |
800 | } | 800 | } |
801 | 801 | ||
802 | static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( | 802 | static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( |
803 | struct t10_wwn *t10_wwn, | 803 | struct t10_wwn *t10_wwn, |
804 | const char *page, | 804 | const char *page, |
805 | size_t count) | 805 | size_t count) |
806 | { | 806 | { |
807 | struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev; | 807 | struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev; |
808 | struct se_device *dev; | 808 | struct se_device *dev; |
809 | unsigned char buf[INQUIRY_VPD_SERIAL_LEN]; | 809 | unsigned char buf[INQUIRY_VPD_SERIAL_LEN]; |
810 | 810 | ||
811 | /* | 811 | /* |
812 | * If Linux/SCSI subsystem_api_t plugin got a VPD Unit Serial | 812 | * If Linux/SCSI subsystem_api_t plugin got a VPD Unit Serial |
813 | * from the struct scsi_device level firmware, do not allow | 813 | * from the struct scsi_device level firmware, do not allow |
814 | * VPD Unit Serial to be emulated. | 814 | * VPD Unit Serial to be emulated. |
815 | * | 815 | * |
816 | * Note this struct scsi_device could also be emulating VPD | 816 | * Note this struct scsi_device could also be emulating VPD |
817 | * information from its drivers/scsi LLD. But for now we assume | 817 | * information from its drivers/scsi LLD. But for now we assume |
818 | * it is doing 'the right thing' wrt a world wide unique | 818 | * it is doing 'the right thing' wrt a world wide unique |
819 | * VPD Unit Serial Number that OS dependent multipath can depend on. | 819 | * VPD Unit Serial Number that OS dependent multipath can depend on. |
820 | */ | 820 | */ |
821 | if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) { | 821 | if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) { |
822 | pr_err("Underlying SCSI device firmware provided VPD" | 822 | pr_err("Underlying SCSI device firmware provided VPD" |
823 | " Unit Serial, ignoring request\n"); | 823 | " Unit Serial, ignoring request\n"); |
824 | return -EOPNOTSUPP; | 824 | return -EOPNOTSUPP; |
825 | } | 825 | } |
826 | 826 | ||
827 | if (strlen(page) >= INQUIRY_VPD_SERIAL_LEN) { | 827 | if (strlen(page) >= INQUIRY_VPD_SERIAL_LEN) { |
828 | pr_err("Emulated VPD Unit Serial exceeds" | 828 | pr_err("Emulated VPD Unit Serial exceeds" |
829 | " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN); | 829 | " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN); |
830 | return -EOVERFLOW; | 830 | return -EOVERFLOW; |
831 | } | 831 | } |
832 | /* | 832 | /* |
833 | * Check to see if any active $FABRIC_MOD exports exist. If they | 833 | * Check to see if any active $FABRIC_MOD exports exist. If they |
834 | * do exist, fail here as changing this information on the fly | 834 | * do exist, fail here as changing this information on the fly |
835 | * (underneath the initiator side OS dependent multipath code) | 835 | * (underneath the initiator side OS dependent multipath code) |
836 | * could cause negative effects. | 836 | * could cause negative effects. |
837 | */ | 837 | */ |
838 | dev = su_dev->se_dev_ptr; | 838 | dev = su_dev->se_dev_ptr; |
839 | if (dev) { | 839 | if (dev) { |
840 | if (atomic_read(&dev->dev_export_obj.obj_access_count)) { | 840 | if (atomic_read(&dev->dev_export_obj.obj_access_count)) { |
841 | pr_err("Unable to set VPD Unit Serial while" | 841 | pr_err("Unable to set VPD Unit Serial while" |
842 | " active %d $FABRIC_MOD exports exist\n", | 842 | " active %d $FABRIC_MOD exports exist\n", |
843 | atomic_read(&dev->dev_export_obj.obj_access_count)); | 843 | atomic_read(&dev->dev_export_obj.obj_access_count)); |
844 | return -EINVAL; | 844 | return -EINVAL; |
845 | } | 845 | } |
846 | } | 846 | } |
847 | /* | 847 | /* |
848 | * This currently assumes ASCII encoding for emulated VPD Unit Serial. | 848 | * This currently assumes ASCII encoding for emulated VPD Unit Serial. |
849 | * | 849 | * |
850 | * Also, strip any newline added from the userspace | 850 | * Also, strip any newline added from the userspace |
851 | * echo $UUID > $TARGET/$HBA/$STORAGE_OBJECT/wwn/vpd_unit_serial | 851 | * echo $UUID > $TARGET/$HBA/$STORAGE_OBJECT/wwn/vpd_unit_serial |
852 | */ | 852 | */ |
853 | memset(buf, 0, INQUIRY_VPD_SERIAL_LEN); | 853 | memset(buf, 0, INQUIRY_VPD_SERIAL_LEN); |
854 | snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page); | 854 | snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page); |
855 | snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN, | 855 | snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN, |
856 | "%s", strstrip(buf)); | 856 | "%s", strstrip(buf)); |
857 | su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL; | 857 | su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL; |
858 | 858 | ||
859 | pr_debug("Target_Core_ConfigFS: Set emulated VPD Unit Serial:" | 859 | pr_debug("Target_Core_ConfigFS: Set emulated VPD Unit Serial:" |
860 | " %s\n", su_dev->t10_wwn.unit_serial); | 860 | " %s\n", su_dev->t10_wwn.unit_serial); |
861 | 861 | ||
862 | return count; | 862 | return count; |
863 | } | 863 | } |
864 | 864 | ||
865 | SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR); | 865 | SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR); |
866 | 866 | ||
867 | /* | 867 | /* |
868 | * VPD page 0x83 Protocol Identifier | 868 | * VPD page 0x83 Protocol Identifier |
869 | */ | 869 | */ |
870 | static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( | 870 | static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( |
871 | struct t10_wwn *t10_wwn, | 871 | struct t10_wwn *t10_wwn, |
872 | char *page) | 872 | char *page) |
873 | { | 873 | { |
874 | struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; | 874 | struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; |
875 | struct se_device *dev; | 875 | struct se_device *dev; |
876 | struct t10_vpd *vpd; | 876 | struct t10_vpd *vpd; |
877 | unsigned char buf[VPD_TMP_BUF_SIZE]; | 877 | unsigned char buf[VPD_TMP_BUF_SIZE]; |
878 | ssize_t len = 0; | 878 | ssize_t len = 0; |
879 | 879 | ||
880 | dev = se_dev->se_dev_ptr; | 880 | dev = se_dev->se_dev_ptr; |
881 | if (!dev) | 881 | if (!dev) |
882 | return -ENODEV; | 882 | return -ENODEV; |
883 | 883 | ||
884 | memset(buf, 0, VPD_TMP_BUF_SIZE); | 884 | memset(buf, 0, VPD_TMP_BUF_SIZE); |
885 | 885 | ||
886 | spin_lock(&t10_wwn->t10_vpd_lock); | 886 | spin_lock(&t10_wwn->t10_vpd_lock); |
887 | list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { | 887 | list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { |
888 | if (!vpd->protocol_identifier_set) | 888 | if (!vpd->protocol_identifier_set) |
889 | continue; | 889 | continue; |
890 | 890 | ||
891 | transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE); | 891 | transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE); |
892 | 892 | ||
893 | if (len + strlen(buf) >= PAGE_SIZE) | 893 | if (len + strlen(buf) >= PAGE_SIZE) |
894 | break; | 894 | break; |
895 | 895 | ||
896 | len += sprintf(page+len, "%s", buf); | 896 | len += sprintf(page+len, "%s", buf); |
897 | } | 897 | } |
898 | spin_unlock(&t10_wwn->t10_vpd_lock); | 898 | spin_unlock(&t10_wwn->t10_vpd_lock); |
899 | 899 | ||
900 | return len; | 900 | return len; |
901 | } | 901 | } |
902 | 902 | ||
903 | static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier( | 903 | static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier( |
904 | struct t10_wwn *t10_wwn, | 904 | struct t10_wwn *t10_wwn, |
905 | const char *page, | 905 | const char *page, |
906 | size_t count) | 906 | size_t count) |
907 | { | 907 | { |
908 | return -ENOSYS; | 908 | return -ENOSYS; |
909 | } | 909 | } |
910 | 910 | ||
911 | SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR); | 911 | SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR); |
912 | 912 | ||
913 | /* | 913 | /* |
914 | * Generic wrapper for dumping VPD identifiers by association. | 914 | * Generic wrapper for dumping VPD identifiers by association. |
915 | */ | 915 | */ |
916 | #define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \ | 916 | #define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \ |
917 | static ssize_t target_core_dev_wwn_show_attr_##_name( \ | 917 | static ssize_t target_core_dev_wwn_show_attr_##_name( \ |
918 | struct t10_wwn *t10_wwn, \ | 918 | struct t10_wwn *t10_wwn, \ |
919 | char *page) \ | 919 | char *page) \ |
920 | { \ | 920 | { \ |
921 | struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; \ | 921 | struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; \ |
922 | struct se_device *dev; \ | 922 | struct se_device *dev; \ |
923 | struct t10_vpd *vpd; \ | 923 | struct t10_vpd *vpd; \ |
924 | unsigned char buf[VPD_TMP_BUF_SIZE]; \ | 924 | unsigned char buf[VPD_TMP_BUF_SIZE]; \ |
925 | ssize_t len = 0; \ | 925 | ssize_t len = 0; \ |
926 | \ | 926 | \ |
927 | dev = se_dev->se_dev_ptr; \ | 927 | dev = se_dev->se_dev_ptr; \ |
928 | if (!dev) \ | 928 | if (!dev) \ |
929 | return -ENODEV; \ | 929 | return -ENODEV; \ |
930 | \ | 930 | \ |
931 | spin_lock(&t10_wwn->t10_vpd_lock); \ | 931 | spin_lock(&t10_wwn->t10_vpd_lock); \ |
932 | list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { \ | 932 | list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { \ |
933 | if (vpd->association != _assoc) \ | 933 | if (vpd->association != _assoc) \ |
934 | continue; \ | 934 | continue; \ |
935 | \ | 935 | \ |
936 | memset(buf, 0, VPD_TMP_BUF_SIZE); \ | 936 | memset(buf, 0, VPD_TMP_BUF_SIZE); \ |
937 | transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE); \ | 937 | transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE); \ |
938 | if (len + strlen(buf) >= PAGE_SIZE) \ | 938 | if (len + strlen(buf) >= PAGE_SIZE) \ |
939 | break; \ | 939 | break; \ |
940 | len += sprintf(page+len, "%s", buf); \ | 940 | len += sprintf(page+len, "%s", buf); \ |
941 | \ | 941 | \ |
942 | memset(buf, 0, VPD_TMP_BUF_SIZE); \ | 942 | memset(buf, 0, VPD_TMP_BUF_SIZE); \ |
943 | transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \ | 943 | transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \ |
944 | if (len + strlen(buf) >= PAGE_SIZE) \ | 944 | if (len + strlen(buf) >= PAGE_SIZE) \ |
945 | break; \ | 945 | break; \ |
946 | len += sprintf(page+len, "%s", buf); \ | 946 | len += sprintf(page+len, "%s", buf); \ |
947 | \ | 947 | \ |
948 | memset(buf, 0, VPD_TMP_BUF_SIZE); \ | 948 | memset(buf, 0, VPD_TMP_BUF_SIZE); \ |
949 | transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \ | 949 | transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \ |
950 | if (len + strlen(buf) >= PAGE_SIZE) \ | 950 | if (len + strlen(buf) >= PAGE_SIZE) \ |
951 | break; \ | 951 | break; \ |
952 | len += sprintf(page+len, "%s", buf); \ | 952 | len += sprintf(page+len, "%s", buf); \ |
953 | } \ | 953 | } \ |
954 | spin_unlock(&t10_wwn->t10_vpd_lock); \ | 954 | spin_unlock(&t10_wwn->t10_vpd_lock); \ |
955 | \ | 955 | \ |
956 | return len; \ | 956 | return len; \ |
957 | } | 957 | } |
958 | 958 | ||
959 | /* | 959 | /* |
960 | * VPD page 0x83 Association: Logical Unit | 960 | * VPD page 0x83 Association: Logical Unit |
961 | */ | 961 | */ |
962 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00); | 962 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00); |
963 | 963 | ||
964 | static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit( | 964 | static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit( |
965 | struct t10_wwn *t10_wwn, | 965 | struct t10_wwn *t10_wwn, |
966 | const char *page, | 966 | const char *page, |
967 | size_t count) | 967 | size_t count) |
968 | { | 968 | { |
969 | return -ENOSYS; | 969 | return -ENOSYS; |
970 | } | 970 | } |
971 | 971 | ||
972 | SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR); | 972 | SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR); |
973 | 973 | ||
974 | /* | 974 | /* |
975 | * VPD page 0x83 Association: Target Port | 975 | * VPD page 0x83 Association: Target Port |
976 | */ | 976 | */ |
977 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10); | 977 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10); |
978 | 978 | ||
979 | static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port( | 979 | static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port( |
980 | struct t10_wwn *t10_wwn, | 980 | struct t10_wwn *t10_wwn, |
981 | const char *page, | 981 | const char *page, |
982 | size_t count) | 982 | size_t count) |
983 | { | 983 | { |
984 | return -ENOSYS; | 984 | return -ENOSYS; |
985 | } | 985 | } |
986 | 986 | ||
987 | SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR); | 987 | SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR); |
988 | 988 | ||
989 | /* | 989 | /* |
990 | * VPD page 0x83 Association: SCSI Target Device | 990 | * VPD page 0x83 Association: SCSI Target Device |
991 | */ | 991 | */ |
992 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20); | 992 | DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20); |
993 | 993 | ||
994 | static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device( | 994 | static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device( |
995 | struct t10_wwn *t10_wwn, | 995 | struct t10_wwn *t10_wwn, |
996 | const char *page, | 996 | const char *page, |
997 | size_t count) | 997 | size_t count) |
998 | { | 998 | { |
999 | return -ENOSYS; | 999 | return -ENOSYS; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR); | 1002 | SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR); |
1003 | 1003 | ||
1004 | CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group); | 1004 | CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group); |
1005 | 1005 | ||
1006 | static struct configfs_attribute *target_core_dev_wwn_attrs[] = { | 1006 | static struct configfs_attribute *target_core_dev_wwn_attrs[] = { |
1007 | &target_core_dev_wwn_vpd_unit_serial.attr, | 1007 | &target_core_dev_wwn_vpd_unit_serial.attr, |
1008 | &target_core_dev_wwn_vpd_protocol_identifier.attr, | 1008 | &target_core_dev_wwn_vpd_protocol_identifier.attr, |
1009 | &target_core_dev_wwn_vpd_assoc_logical_unit.attr, | 1009 | &target_core_dev_wwn_vpd_assoc_logical_unit.attr, |
1010 | &target_core_dev_wwn_vpd_assoc_target_port.attr, | 1010 | &target_core_dev_wwn_vpd_assoc_target_port.attr, |
1011 | &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr, | 1011 | &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr, |
1012 | NULL, | 1012 | NULL, |
1013 | }; | 1013 | }; |
1014 | 1014 | ||
1015 | static struct configfs_item_operations target_core_dev_wwn_ops = { | 1015 | static struct configfs_item_operations target_core_dev_wwn_ops = { |
1016 | .show_attribute = target_core_dev_wwn_attr_show, | 1016 | .show_attribute = target_core_dev_wwn_attr_show, |
1017 | .store_attribute = target_core_dev_wwn_attr_store, | 1017 | .store_attribute = target_core_dev_wwn_attr_store, |
1018 | }; | 1018 | }; |
1019 | 1019 | ||
1020 | static struct config_item_type target_core_dev_wwn_cit = { | 1020 | static struct config_item_type target_core_dev_wwn_cit = { |
1021 | .ct_item_ops = &target_core_dev_wwn_ops, | 1021 | .ct_item_ops = &target_core_dev_wwn_ops, |
1022 | .ct_attrs = target_core_dev_wwn_attrs, | 1022 | .ct_attrs = target_core_dev_wwn_attrs, |
1023 | .ct_owner = THIS_MODULE, | 1023 | .ct_owner = THIS_MODULE, |
1024 | }; | 1024 | }; |
1025 | 1025 | ||
1026 | /* End functions for struct config_item_type target_core_dev_wwn_cit */ | 1026 | /* End functions for struct config_item_type target_core_dev_wwn_cit */ |
1027 | 1027 | ||
1028 | /* Start functions for struct config_item_type target_core_dev_pr_cit */ | 1028 | /* Start functions for struct config_item_type target_core_dev_pr_cit */ |
1029 | 1029 | ||
1030 | CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev); | 1030 | CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev); |
1031 | #define SE_DEV_PR_ATTR(_name, _mode) \ | 1031 | #define SE_DEV_PR_ATTR(_name, _mode) \ |
1032 | static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ | 1032 | static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ |
1033 | __CONFIGFS_EATTR(_name, _mode, \ | 1033 | __CONFIGFS_EATTR(_name, _mode, \ |
1034 | target_core_dev_pr_show_attr_##_name, \ | 1034 | target_core_dev_pr_show_attr_##_name, \ |
1035 | target_core_dev_pr_store_attr_##_name); | 1035 | target_core_dev_pr_store_attr_##_name); |
1036 | 1036 | ||
1037 | #define SE_DEV_PR_ATTR_RO(_name); \ | 1037 | #define SE_DEV_PR_ATTR_RO(_name); \ |
1038 | static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ | 1038 | static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ |
1039 | __CONFIGFS_EATTR_RO(_name, \ | 1039 | __CONFIGFS_EATTR_RO(_name, \ |
1040 | target_core_dev_pr_show_attr_##_name); | 1040 | target_core_dev_pr_show_attr_##_name); |
1041 | 1041 | ||
1042 | /* | 1042 | /* |
1043 | * res_holder | 1043 | * res_holder |
1044 | */ | 1044 | */ |
1045 | static ssize_t target_core_dev_pr_show_spc3_res( | 1045 | static ssize_t target_core_dev_pr_show_spc3_res( |
1046 | struct se_device *dev, | 1046 | struct se_device *dev, |
1047 | char *page, | 1047 | char *page, |
1048 | ssize_t *len) | 1048 | ssize_t *len) |
1049 | { | 1049 | { |
1050 | struct se_node_acl *se_nacl; | 1050 | struct se_node_acl *se_nacl; |
1051 | struct t10_pr_registration *pr_reg; | 1051 | struct t10_pr_registration *pr_reg; |
1052 | char i_buf[PR_REG_ISID_ID_LEN]; | 1052 | char i_buf[PR_REG_ISID_ID_LEN]; |
1053 | int prf_isid; | 1053 | int prf_isid; |
1054 | 1054 | ||
1055 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 1055 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
1056 | 1056 | ||
1057 | spin_lock(&dev->dev_reservation_lock); | 1057 | spin_lock(&dev->dev_reservation_lock); |
1058 | pr_reg = dev->dev_pr_res_holder; | 1058 | pr_reg = dev->dev_pr_res_holder; |
1059 | if (!pr_reg) { | 1059 | if (!pr_reg) { |
1060 | *len += sprintf(page + *len, "No SPC-3 Reservation holder\n"); | 1060 | *len += sprintf(page + *len, "No SPC-3 Reservation holder\n"); |
1061 | spin_unlock(&dev->dev_reservation_lock); | 1061 | spin_unlock(&dev->dev_reservation_lock); |
1062 | return *len; | 1062 | return *len; |
1063 | } | 1063 | } |
1064 | se_nacl = pr_reg->pr_reg_nacl; | 1064 | se_nacl = pr_reg->pr_reg_nacl; |
1065 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 1065 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
1066 | PR_REG_ISID_ID_LEN); | 1066 | PR_REG_ISID_ID_LEN); |
1067 | 1067 | ||
1068 | *len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n", | 1068 | *len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n", |
1069 | se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), | 1069 | se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
1070 | se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); | 1070 | se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); |
1071 | spin_unlock(&dev->dev_reservation_lock); | 1071 | spin_unlock(&dev->dev_reservation_lock); |
1072 | 1072 | ||
1073 | return *len; | 1073 | return *len; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | static ssize_t target_core_dev_pr_show_spc2_res( | 1076 | static ssize_t target_core_dev_pr_show_spc2_res( |
1077 | struct se_device *dev, | 1077 | struct se_device *dev, |
1078 | char *page, | 1078 | char *page, |
1079 | ssize_t *len) | 1079 | ssize_t *len) |
1080 | { | 1080 | { |
1081 | struct se_node_acl *se_nacl; | 1081 | struct se_node_acl *se_nacl; |
1082 | 1082 | ||
1083 | spin_lock(&dev->dev_reservation_lock); | 1083 | spin_lock(&dev->dev_reservation_lock); |
1084 | se_nacl = dev->dev_reserved_node_acl; | 1084 | se_nacl = dev->dev_reserved_node_acl; |
1085 | if (!se_nacl) { | 1085 | if (!se_nacl) { |
1086 | *len += sprintf(page + *len, "No SPC-2 Reservation holder\n"); | 1086 | *len += sprintf(page + *len, "No SPC-2 Reservation holder\n"); |
1087 | spin_unlock(&dev->dev_reservation_lock); | 1087 | spin_unlock(&dev->dev_reservation_lock); |
1088 | return *len; | 1088 | return *len; |
1089 | } | 1089 | } |
1090 | *len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n", | 1090 | *len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n", |
1091 | se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), | 1091 | se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
1092 | se_nacl->initiatorname); | 1092 | se_nacl->initiatorname); |
1093 | spin_unlock(&dev->dev_reservation_lock); | 1093 | spin_unlock(&dev->dev_reservation_lock); |
1094 | 1094 | ||
1095 | return *len; | 1095 | return *len; |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | static ssize_t target_core_dev_pr_show_attr_res_holder( | 1098 | static ssize_t target_core_dev_pr_show_attr_res_holder( |
1099 | struct se_subsystem_dev *su_dev, | 1099 | struct se_subsystem_dev *su_dev, |
1100 | char *page) | 1100 | char *page) |
1101 | { | 1101 | { |
1102 | ssize_t len = 0; | 1102 | ssize_t len = 0; |
1103 | 1103 | ||
1104 | if (!su_dev->se_dev_ptr) | 1104 | if (!su_dev->se_dev_ptr) |
1105 | return -ENODEV; | 1105 | return -ENODEV; |
1106 | 1106 | ||
1107 | switch (su_dev->t10_pr.res_type) { | 1107 | switch (su_dev->t10_pr.res_type) { |
1108 | case SPC3_PERSISTENT_RESERVATIONS: | 1108 | case SPC3_PERSISTENT_RESERVATIONS: |
1109 | target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr, | 1109 | target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr, |
1110 | page, &len); | 1110 | page, &len); |
1111 | break; | 1111 | break; |
1112 | case SPC2_RESERVATIONS: | 1112 | case SPC2_RESERVATIONS: |
1113 | target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr, | 1113 | target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr, |
1114 | page, &len); | 1114 | page, &len); |
1115 | break; | 1115 | break; |
1116 | case SPC_PASSTHROUGH: | 1116 | case SPC_PASSTHROUGH: |
1117 | len += sprintf(page+len, "Passthrough\n"); | 1117 | len += sprintf(page+len, "Passthrough\n"); |
1118 | break; | 1118 | break; |
1119 | default: | 1119 | default: |
1120 | len += sprintf(page+len, "Unknown\n"); | 1120 | len += sprintf(page+len, "Unknown\n"); |
1121 | break; | 1121 | break; |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | return len; | 1124 | return len; |
1125 | } | 1125 | } |
1126 | 1126 | ||
1127 | SE_DEV_PR_ATTR_RO(res_holder); | 1127 | SE_DEV_PR_ATTR_RO(res_holder); |
1128 | 1128 | ||
1129 | /* | 1129 | /* |
1130 | * res_pr_all_tgt_pts | 1130 | * res_pr_all_tgt_pts |
1131 | */ | 1131 | */ |
1132 | static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( | 1132 | static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( |
1133 | struct se_subsystem_dev *su_dev, | 1133 | struct se_subsystem_dev *su_dev, |
1134 | char *page) | 1134 | char *page) |
1135 | { | 1135 | { |
1136 | struct se_device *dev; | 1136 | struct se_device *dev; |
1137 | struct t10_pr_registration *pr_reg; | 1137 | struct t10_pr_registration *pr_reg; |
1138 | ssize_t len = 0; | 1138 | ssize_t len = 0; |
1139 | 1139 | ||
1140 | dev = su_dev->se_dev_ptr; | 1140 | dev = su_dev->se_dev_ptr; |
1141 | if (!dev) | 1141 | if (!dev) |
1142 | return -ENODEV; | 1142 | return -ENODEV; |
1143 | 1143 | ||
1144 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1144 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1145 | return len; | 1145 | return len; |
1146 | 1146 | ||
1147 | spin_lock(&dev->dev_reservation_lock); | 1147 | spin_lock(&dev->dev_reservation_lock); |
1148 | pr_reg = dev->dev_pr_res_holder; | 1148 | pr_reg = dev->dev_pr_res_holder; |
1149 | if (!pr_reg) { | 1149 | if (!pr_reg) { |
1150 | len = sprintf(page, "No SPC-3 Reservation holder\n"); | 1150 | len = sprintf(page, "No SPC-3 Reservation holder\n"); |
1151 | spin_unlock(&dev->dev_reservation_lock); | 1151 | spin_unlock(&dev->dev_reservation_lock); |
1152 | return len; | 1152 | return len; |
1153 | } | 1153 | } |
1154 | /* | 1154 | /* |
1155 | * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3 | 1155 | * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3 |
1156 | * Basic PERSISTENT RESERVER OUT parameter list, page 290 | 1156 | * Basic PERSISTENT RESERVER OUT parameter list, page 290 |
1157 | */ | 1157 | */ |
1158 | if (pr_reg->pr_reg_all_tg_pt) | 1158 | if (pr_reg->pr_reg_all_tg_pt) |
1159 | len = sprintf(page, "SPC-3 Reservation: All Target" | 1159 | len = sprintf(page, "SPC-3 Reservation: All Target" |
1160 | " Ports registration\n"); | 1160 | " Ports registration\n"); |
1161 | else | 1161 | else |
1162 | len = sprintf(page, "SPC-3 Reservation: Single" | 1162 | len = sprintf(page, "SPC-3 Reservation: Single" |
1163 | " Target Port registration\n"); | 1163 | " Target Port registration\n"); |
1164 | spin_unlock(&dev->dev_reservation_lock); | 1164 | spin_unlock(&dev->dev_reservation_lock); |
1165 | 1165 | ||
1166 | return len; | 1166 | return len; |
1167 | } | 1167 | } |
1168 | 1168 | ||
1169 | SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts); | 1169 | SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts); |
1170 | 1170 | ||
1171 | /* | 1171 | /* |
1172 | * res_pr_generation | 1172 | * res_pr_generation |
1173 | */ | 1173 | */ |
1174 | static ssize_t target_core_dev_pr_show_attr_res_pr_generation( | 1174 | static ssize_t target_core_dev_pr_show_attr_res_pr_generation( |
1175 | struct se_subsystem_dev *su_dev, | 1175 | struct se_subsystem_dev *su_dev, |
1176 | char *page) | 1176 | char *page) |
1177 | { | 1177 | { |
1178 | if (!su_dev->se_dev_ptr) | 1178 | if (!su_dev->se_dev_ptr) |
1179 | return -ENODEV; | 1179 | return -ENODEV; |
1180 | 1180 | ||
1181 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1181 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1182 | return 0; | 1182 | return 0; |
1183 | 1183 | ||
1184 | return sprintf(page, "0x%08x\n", su_dev->t10_pr.pr_generation); | 1184 | return sprintf(page, "0x%08x\n", su_dev->t10_pr.pr_generation); |
1185 | } | 1185 | } |
1186 | 1186 | ||
1187 | SE_DEV_PR_ATTR_RO(res_pr_generation); | 1187 | SE_DEV_PR_ATTR_RO(res_pr_generation); |
1188 | 1188 | ||
1189 | /* | 1189 | /* |
1190 | * res_pr_holder_tg_port | 1190 | * res_pr_holder_tg_port |
1191 | */ | 1191 | */ |
1192 | static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( | 1192 | static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( |
1193 | struct se_subsystem_dev *su_dev, | 1193 | struct se_subsystem_dev *su_dev, |
1194 | char *page) | 1194 | char *page) |
1195 | { | 1195 | { |
1196 | struct se_device *dev; | 1196 | struct se_device *dev; |
1197 | struct se_node_acl *se_nacl; | 1197 | struct se_node_acl *se_nacl; |
1198 | struct se_lun *lun; | 1198 | struct se_lun *lun; |
1199 | struct se_portal_group *se_tpg; | 1199 | struct se_portal_group *se_tpg; |
1200 | struct t10_pr_registration *pr_reg; | 1200 | struct t10_pr_registration *pr_reg; |
1201 | struct target_core_fabric_ops *tfo; | 1201 | struct target_core_fabric_ops *tfo; |
1202 | ssize_t len = 0; | 1202 | ssize_t len = 0; |
1203 | 1203 | ||
1204 | dev = su_dev->se_dev_ptr; | 1204 | dev = su_dev->se_dev_ptr; |
1205 | if (!dev) | 1205 | if (!dev) |
1206 | return -ENODEV; | 1206 | return -ENODEV; |
1207 | 1207 | ||
1208 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1208 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1209 | return len; | 1209 | return len; |
1210 | 1210 | ||
1211 | spin_lock(&dev->dev_reservation_lock); | 1211 | spin_lock(&dev->dev_reservation_lock); |
1212 | pr_reg = dev->dev_pr_res_holder; | 1212 | pr_reg = dev->dev_pr_res_holder; |
1213 | if (!pr_reg) { | 1213 | if (!pr_reg) { |
1214 | len = sprintf(page, "No SPC-3 Reservation holder\n"); | 1214 | len = sprintf(page, "No SPC-3 Reservation holder\n"); |
1215 | spin_unlock(&dev->dev_reservation_lock); | 1215 | spin_unlock(&dev->dev_reservation_lock); |
1216 | return len; | 1216 | return len; |
1217 | } | 1217 | } |
1218 | se_nacl = pr_reg->pr_reg_nacl; | 1218 | se_nacl = pr_reg->pr_reg_nacl; |
1219 | se_tpg = se_nacl->se_tpg; | 1219 | se_tpg = se_nacl->se_tpg; |
1220 | lun = pr_reg->pr_reg_tg_pt_lun; | 1220 | lun = pr_reg->pr_reg_tg_pt_lun; |
1221 | tfo = se_tpg->se_tpg_tfo; | 1221 | tfo = se_tpg->se_tpg_tfo; |
1222 | 1222 | ||
1223 | len += sprintf(page+len, "SPC-3 Reservation: %s" | 1223 | len += sprintf(page+len, "SPC-3 Reservation: %s" |
1224 | " Target Node Endpoint: %s\n", tfo->get_fabric_name(), | 1224 | " Target Node Endpoint: %s\n", tfo->get_fabric_name(), |
1225 | tfo->tpg_get_wwn(se_tpg)); | 1225 | tfo->tpg_get_wwn(se_tpg)); |
1226 | len += sprintf(page+len, "SPC-3 Reservation: Relative Port" | 1226 | len += sprintf(page+len, "SPC-3 Reservation: Relative Port" |
1227 | " Identifer Tag: %hu %s Portal Group Tag: %hu" | 1227 | " Identifer Tag: %hu %s Portal Group Tag: %hu" |
1228 | " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi, | 1228 | " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi, |
1229 | tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), | 1229 | tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), |
1230 | tfo->get_fabric_name(), lun->unpacked_lun); | 1230 | tfo->get_fabric_name(), lun->unpacked_lun); |
1231 | spin_unlock(&dev->dev_reservation_lock); | 1231 | spin_unlock(&dev->dev_reservation_lock); |
1232 | 1232 | ||
1233 | return len; | 1233 | return len; |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); | 1236 | SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); |
1237 | 1237 | ||
1238 | /* | 1238 | /* |
1239 | * res_pr_registered_i_pts | 1239 | * res_pr_registered_i_pts |
1240 | */ | 1240 | */ |
1241 | static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( | 1241 | static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( |
1242 | struct se_subsystem_dev *su_dev, | 1242 | struct se_subsystem_dev *su_dev, |
1243 | char *page) | 1243 | char *page) |
1244 | { | 1244 | { |
1245 | struct target_core_fabric_ops *tfo; | 1245 | struct target_core_fabric_ops *tfo; |
1246 | struct t10_pr_registration *pr_reg; | 1246 | struct t10_pr_registration *pr_reg; |
1247 | unsigned char buf[384]; | 1247 | unsigned char buf[384]; |
1248 | char i_buf[PR_REG_ISID_ID_LEN]; | 1248 | char i_buf[PR_REG_ISID_ID_LEN]; |
1249 | ssize_t len = 0; | 1249 | ssize_t len = 0; |
1250 | int reg_count = 0, prf_isid; | 1250 | int reg_count = 0, prf_isid; |
1251 | 1251 | ||
1252 | if (!su_dev->se_dev_ptr) | 1252 | if (!su_dev->se_dev_ptr) |
1253 | return -ENODEV; | 1253 | return -ENODEV; |
1254 | 1254 | ||
1255 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1255 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1256 | return len; | 1256 | return len; |
1257 | 1257 | ||
1258 | len += sprintf(page+len, "SPC-3 PR Registrations:\n"); | 1258 | len += sprintf(page+len, "SPC-3 PR Registrations:\n"); |
1259 | 1259 | ||
1260 | spin_lock(&su_dev->t10_pr.registration_lock); | 1260 | spin_lock(&su_dev->t10_pr.registration_lock); |
1261 | list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, | 1261 | list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, |
1262 | pr_reg_list) { | 1262 | pr_reg_list) { |
1263 | 1263 | ||
1264 | memset(buf, 0, 384); | 1264 | memset(buf, 0, 384); |
1265 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 1265 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
1266 | tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; | 1266 | tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; |
1267 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 1267 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
1268 | PR_REG_ISID_ID_LEN); | 1268 | PR_REG_ISID_ID_LEN); |
1269 | sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n", | 1269 | sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n", |
1270 | tfo->get_fabric_name(), | 1270 | tfo->get_fabric_name(), |
1271 | pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ? | 1271 | pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ? |
1272 | &i_buf[0] : "", pr_reg->pr_res_key, | 1272 | &i_buf[0] : "", pr_reg->pr_res_key, |
1273 | pr_reg->pr_res_generation); | 1273 | pr_reg->pr_res_generation); |
1274 | 1274 | ||
1275 | if (len + strlen(buf) >= PAGE_SIZE) | 1275 | if (len + strlen(buf) >= PAGE_SIZE) |
1276 | break; | 1276 | break; |
1277 | 1277 | ||
1278 | len += sprintf(page+len, "%s", buf); | 1278 | len += sprintf(page+len, "%s", buf); |
1279 | reg_count++; | 1279 | reg_count++; |
1280 | } | 1280 | } |
1281 | spin_unlock(&su_dev->t10_pr.registration_lock); | 1281 | spin_unlock(&su_dev->t10_pr.registration_lock); |
1282 | 1282 | ||
1283 | if (!reg_count) | 1283 | if (!reg_count) |
1284 | len += sprintf(page+len, "None\n"); | 1284 | len += sprintf(page+len, "None\n"); |
1285 | 1285 | ||
1286 | return len; | 1286 | return len; |
1287 | } | 1287 | } |
1288 | 1288 | ||
1289 | SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts); | 1289 | SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts); |
1290 | 1290 | ||
1291 | /* | 1291 | /* |
1292 | * res_pr_type | 1292 | * res_pr_type |
1293 | */ | 1293 | */ |
1294 | static ssize_t target_core_dev_pr_show_attr_res_pr_type( | 1294 | static ssize_t target_core_dev_pr_show_attr_res_pr_type( |
1295 | struct se_subsystem_dev *su_dev, | 1295 | struct se_subsystem_dev *su_dev, |
1296 | char *page) | 1296 | char *page) |
1297 | { | 1297 | { |
1298 | struct se_device *dev; | 1298 | struct se_device *dev; |
1299 | struct t10_pr_registration *pr_reg; | 1299 | struct t10_pr_registration *pr_reg; |
1300 | ssize_t len = 0; | 1300 | ssize_t len = 0; |
1301 | 1301 | ||
1302 | dev = su_dev->se_dev_ptr; | 1302 | dev = su_dev->se_dev_ptr; |
1303 | if (!dev) | 1303 | if (!dev) |
1304 | return -ENODEV; | 1304 | return -ENODEV; |
1305 | 1305 | ||
1306 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1306 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1307 | return len; | 1307 | return len; |
1308 | 1308 | ||
1309 | spin_lock(&dev->dev_reservation_lock); | 1309 | spin_lock(&dev->dev_reservation_lock); |
1310 | pr_reg = dev->dev_pr_res_holder; | 1310 | pr_reg = dev->dev_pr_res_holder; |
1311 | if (!pr_reg) { | 1311 | if (!pr_reg) { |
1312 | len = sprintf(page, "No SPC-3 Reservation holder\n"); | 1312 | len = sprintf(page, "No SPC-3 Reservation holder\n"); |
1313 | spin_unlock(&dev->dev_reservation_lock); | 1313 | spin_unlock(&dev->dev_reservation_lock); |
1314 | return len; | 1314 | return len; |
1315 | } | 1315 | } |
1316 | len = sprintf(page, "SPC-3 Reservation Type: %s\n", | 1316 | len = sprintf(page, "SPC-3 Reservation Type: %s\n", |
1317 | core_scsi3_pr_dump_type(pr_reg->pr_res_type)); | 1317 | core_scsi3_pr_dump_type(pr_reg->pr_res_type)); |
1318 | spin_unlock(&dev->dev_reservation_lock); | 1318 | spin_unlock(&dev->dev_reservation_lock); |
1319 | 1319 | ||
1320 | return len; | 1320 | return len; |
1321 | } | 1321 | } |
1322 | 1322 | ||
1323 | SE_DEV_PR_ATTR_RO(res_pr_type); | 1323 | SE_DEV_PR_ATTR_RO(res_pr_type); |
1324 | 1324 | ||
1325 | /* | 1325 | /* |
1326 | * res_type | 1326 | * res_type |
1327 | */ | 1327 | */ |
1328 | static ssize_t target_core_dev_pr_show_attr_res_type( | 1328 | static ssize_t target_core_dev_pr_show_attr_res_type( |
1329 | struct se_subsystem_dev *su_dev, | 1329 | struct se_subsystem_dev *su_dev, |
1330 | char *page) | 1330 | char *page) |
1331 | { | 1331 | { |
1332 | ssize_t len = 0; | 1332 | ssize_t len = 0; |
1333 | 1333 | ||
1334 | if (!su_dev->se_dev_ptr) | 1334 | if (!su_dev->se_dev_ptr) |
1335 | return -ENODEV; | 1335 | return -ENODEV; |
1336 | 1336 | ||
1337 | switch (su_dev->t10_pr.res_type) { | 1337 | switch (su_dev->t10_pr.res_type) { |
1338 | case SPC3_PERSISTENT_RESERVATIONS: | 1338 | case SPC3_PERSISTENT_RESERVATIONS: |
1339 | len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); | 1339 | len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); |
1340 | break; | 1340 | break; |
1341 | case SPC2_RESERVATIONS: | 1341 | case SPC2_RESERVATIONS: |
1342 | len = sprintf(page, "SPC2_RESERVATIONS\n"); | 1342 | len = sprintf(page, "SPC2_RESERVATIONS\n"); |
1343 | break; | 1343 | break; |
1344 | case SPC_PASSTHROUGH: | 1344 | case SPC_PASSTHROUGH: |
1345 | len = sprintf(page, "SPC_PASSTHROUGH\n"); | 1345 | len = sprintf(page, "SPC_PASSTHROUGH\n"); |
1346 | break; | 1346 | break; |
1347 | default: | 1347 | default: |
1348 | len = sprintf(page, "UNKNOWN\n"); | 1348 | len = sprintf(page, "UNKNOWN\n"); |
1349 | break; | 1349 | break; |
1350 | } | 1350 | } |
1351 | 1351 | ||
1352 | return len; | 1352 | return len; |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | SE_DEV_PR_ATTR_RO(res_type); | 1355 | SE_DEV_PR_ATTR_RO(res_type); |
1356 | 1356 | ||
1357 | /* | 1357 | /* |
1358 | * res_aptpl_active | 1358 | * res_aptpl_active |
1359 | */ | 1359 | */ |
1360 | 1360 | ||
1361 | static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( | 1361 | static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( |
1362 | struct se_subsystem_dev *su_dev, | 1362 | struct se_subsystem_dev *su_dev, |
1363 | char *page) | 1363 | char *page) |
1364 | { | 1364 | { |
1365 | if (!su_dev->se_dev_ptr) | 1365 | if (!su_dev->se_dev_ptr) |
1366 | return -ENODEV; | 1366 | return -ENODEV; |
1367 | 1367 | ||
1368 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1368 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1369 | return 0; | 1369 | return 0; |
1370 | 1370 | ||
1371 | return sprintf(page, "APTPL Bit Status: %s\n", | 1371 | return sprintf(page, "APTPL Bit Status: %s\n", |
1372 | (su_dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled"); | 1372 | (su_dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled"); |
1373 | } | 1373 | } |
1374 | 1374 | ||
1375 | SE_DEV_PR_ATTR_RO(res_aptpl_active); | 1375 | SE_DEV_PR_ATTR_RO(res_aptpl_active); |
1376 | 1376 | ||
1377 | /* | 1377 | /* |
1378 | * res_aptpl_metadata | 1378 | * res_aptpl_metadata |
1379 | */ | 1379 | */ |
1380 | static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( | 1380 | static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( |
1381 | struct se_subsystem_dev *su_dev, | 1381 | struct se_subsystem_dev *su_dev, |
1382 | char *page) | 1382 | char *page) |
1383 | { | 1383 | { |
1384 | if (!su_dev->se_dev_ptr) | 1384 | if (!su_dev->se_dev_ptr) |
1385 | return -ENODEV; | 1385 | return -ENODEV; |
1386 | 1386 | ||
1387 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1387 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1388 | return 0; | 1388 | return 0; |
1389 | 1389 | ||
1390 | return sprintf(page, "Ready to process PR APTPL metadata..\n"); | 1390 | return sprintf(page, "Ready to process PR APTPL metadata..\n"); |
1391 | } | 1391 | } |
1392 | 1392 | ||
1393 | enum { | 1393 | enum { |
1394 | Opt_initiator_fabric, Opt_initiator_node, Opt_initiator_sid, | 1394 | Opt_initiator_fabric, Opt_initiator_node, Opt_initiator_sid, |
1395 | Opt_sa_res_key, Opt_res_holder, Opt_res_type, Opt_res_scope, | 1395 | Opt_sa_res_key, Opt_res_holder, Opt_res_type, Opt_res_scope, |
1396 | Opt_res_all_tg_pt, Opt_mapped_lun, Opt_target_fabric, | 1396 | Opt_res_all_tg_pt, Opt_mapped_lun, Opt_target_fabric, |
1397 | Opt_target_node, Opt_tpgt, Opt_port_rtpi, Opt_target_lun, Opt_err | 1397 | Opt_target_node, Opt_tpgt, Opt_port_rtpi, Opt_target_lun, Opt_err |
1398 | }; | 1398 | }; |
1399 | 1399 | ||
1400 | static match_table_t tokens = { | 1400 | static match_table_t tokens = { |
1401 | {Opt_initiator_fabric, "initiator_fabric=%s"}, | 1401 | {Opt_initiator_fabric, "initiator_fabric=%s"}, |
1402 | {Opt_initiator_node, "initiator_node=%s"}, | 1402 | {Opt_initiator_node, "initiator_node=%s"}, |
1403 | {Opt_initiator_sid, "initiator_sid=%s"}, | 1403 | {Opt_initiator_sid, "initiator_sid=%s"}, |
1404 | {Opt_sa_res_key, "sa_res_key=%s"}, | 1404 | {Opt_sa_res_key, "sa_res_key=%s"}, |
1405 | {Opt_res_holder, "res_holder=%d"}, | 1405 | {Opt_res_holder, "res_holder=%d"}, |
1406 | {Opt_res_type, "res_type=%d"}, | 1406 | {Opt_res_type, "res_type=%d"}, |
1407 | {Opt_res_scope, "res_scope=%d"}, | 1407 | {Opt_res_scope, "res_scope=%d"}, |
1408 | {Opt_res_all_tg_pt, "res_all_tg_pt=%d"}, | 1408 | {Opt_res_all_tg_pt, "res_all_tg_pt=%d"}, |
1409 | {Opt_mapped_lun, "mapped_lun=%d"}, | 1409 | {Opt_mapped_lun, "mapped_lun=%d"}, |
1410 | {Opt_target_fabric, "target_fabric=%s"}, | 1410 | {Opt_target_fabric, "target_fabric=%s"}, |
1411 | {Opt_target_node, "target_node=%s"}, | 1411 | {Opt_target_node, "target_node=%s"}, |
1412 | {Opt_tpgt, "tpgt=%d"}, | 1412 | {Opt_tpgt, "tpgt=%d"}, |
1413 | {Opt_port_rtpi, "port_rtpi=%d"}, | 1413 | {Opt_port_rtpi, "port_rtpi=%d"}, |
1414 | {Opt_target_lun, "target_lun=%d"}, | 1414 | {Opt_target_lun, "target_lun=%d"}, |
1415 | {Opt_err, NULL} | 1415 | {Opt_err, NULL} |
1416 | }; | 1416 | }; |
1417 | 1417 | ||
1418 | static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | 1418 | static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( |
1419 | struct se_subsystem_dev *su_dev, | 1419 | struct se_subsystem_dev *su_dev, |
1420 | const char *page, | 1420 | const char *page, |
1421 | size_t count) | 1421 | size_t count) |
1422 | { | 1422 | { |
1423 | struct se_device *dev; | 1423 | struct se_device *dev; |
1424 | unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; | 1424 | unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; |
1425 | unsigned char *t_fabric = NULL, *t_port = NULL; | 1425 | unsigned char *t_fabric = NULL, *t_port = NULL; |
1426 | char *orig, *ptr, *arg_p, *opts; | 1426 | char *orig, *ptr, *arg_p, *opts; |
1427 | substring_t args[MAX_OPT_ARGS]; | 1427 | substring_t args[MAX_OPT_ARGS]; |
1428 | unsigned long long tmp_ll; | 1428 | unsigned long long tmp_ll; |
1429 | u64 sa_res_key = 0; | 1429 | u64 sa_res_key = 0; |
1430 | u32 mapped_lun = 0, target_lun = 0; | 1430 | u32 mapped_lun = 0, target_lun = 0; |
1431 | int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token; | 1431 | int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token; |
1432 | u16 port_rpti = 0, tpgt = 0; | 1432 | u16 port_rpti = 0, tpgt = 0; |
1433 | u8 type = 0, scope; | 1433 | u8 type = 0, scope; |
1434 | 1434 | ||
1435 | dev = su_dev->se_dev_ptr; | 1435 | dev = su_dev->se_dev_ptr; |
1436 | if (!dev) | 1436 | if (!dev) |
1437 | return -ENODEV; | 1437 | return -ENODEV; |
1438 | 1438 | ||
1439 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 1439 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
1440 | return 0; | 1440 | return 0; |
1441 | 1441 | ||
1442 | if (atomic_read(&dev->dev_export_obj.obj_access_count)) { | 1442 | if (atomic_read(&dev->dev_export_obj.obj_access_count)) { |
1443 | pr_debug("Unable to process APTPL metadata while" | 1443 | pr_debug("Unable to process APTPL metadata while" |
1444 | " active fabric exports exist\n"); | 1444 | " active fabric exports exist\n"); |
1445 | return -EINVAL; | 1445 | return -EINVAL; |
1446 | } | 1446 | } |
1447 | 1447 | ||
1448 | opts = kstrdup(page, GFP_KERNEL); | 1448 | opts = kstrdup(page, GFP_KERNEL); |
1449 | if (!opts) | 1449 | if (!opts) |
1450 | return -ENOMEM; | 1450 | return -ENOMEM; |
1451 | 1451 | ||
1452 | orig = opts; | 1452 | orig = opts; |
1453 | while ((ptr = strsep(&opts, ",\n")) != NULL) { | 1453 | while ((ptr = strsep(&opts, ",\n")) != NULL) { |
1454 | if (!*ptr) | 1454 | if (!*ptr) |
1455 | continue; | 1455 | continue; |
1456 | 1456 | ||
1457 | token = match_token(ptr, tokens, args); | 1457 | token = match_token(ptr, tokens, args); |
1458 | switch (token) { | 1458 | switch (token) { |
1459 | case Opt_initiator_fabric: | 1459 | case Opt_initiator_fabric: |
1460 | i_fabric = match_strdup(&args[0]); | 1460 | i_fabric = match_strdup(&args[0]); |
1461 | if (!i_fabric) { | 1461 | if (!i_fabric) { |
1462 | ret = -ENOMEM; | 1462 | ret = -ENOMEM; |
1463 | goto out; | 1463 | goto out; |
1464 | } | 1464 | } |
1465 | break; | 1465 | break; |
1466 | case Opt_initiator_node: | 1466 | case Opt_initiator_node: |
1467 | i_port = match_strdup(&args[0]); | 1467 | i_port = match_strdup(&args[0]); |
1468 | if (!i_port) { | 1468 | if (!i_port) { |
1469 | ret = -ENOMEM; | 1469 | ret = -ENOMEM; |
1470 | goto out; | 1470 | goto out; |
1471 | } | 1471 | } |
1472 | if (strlen(i_port) >= PR_APTPL_MAX_IPORT_LEN) { | 1472 | if (strlen(i_port) >= PR_APTPL_MAX_IPORT_LEN) { |
1473 | pr_err("APTPL metadata initiator_node=" | 1473 | pr_err("APTPL metadata initiator_node=" |
1474 | " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", | 1474 | " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", |
1475 | PR_APTPL_MAX_IPORT_LEN); | 1475 | PR_APTPL_MAX_IPORT_LEN); |
1476 | ret = -EINVAL; | 1476 | ret = -EINVAL; |
1477 | break; | 1477 | break; |
1478 | } | 1478 | } |
1479 | break; | 1479 | break; |
1480 | case Opt_initiator_sid: | 1480 | case Opt_initiator_sid: |
1481 | isid = match_strdup(&args[0]); | 1481 | isid = match_strdup(&args[0]); |
1482 | if (!isid) { | 1482 | if (!isid) { |
1483 | ret = -ENOMEM; | 1483 | ret = -ENOMEM; |
1484 | goto out; | 1484 | goto out; |
1485 | } | 1485 | } |
1486 | if (strlen(isid) >= PR_REG_ISID_LEN) { | 1486 | if (strlen(isid) >= PR_REG_ISID_LEN) { |
1487 | pr_err("APTPL metadata initiator_isid" | 1487 | pr_err("APTPL metadata initiator_isid" |
1488 | "= exceeds PR_REG_ISID_LEN: %d\n", | 1488 | "= exceeds PR_REG_ISID_LEN: %d\n", |
1489 | PR_REG_ISID_LEN); | 1489 | PR_REG_ISID_LEN); |
1490 | ret = -EINVAL; | 1490 | ret = -EINVAL; |
1491 | break; | 1491 | break; |
1492 | } | 1492 | } |
1493 | break; | 1493 | break; |
1494 | case Opt_sa_res_key: | 1494 | case Opt_sa_res_key: |
1495 | arg_p = match_strdup(&args[0]); | 1495 | arg_p = match_strdup(&args[0]); |
1496 | if (!arg_p) { | 1496 | if (!arg_p) { |
1497 | ret = -ENOMEM; | 1497 | ret = -ENOMEM; |
1498 | goto out; | 1498 | goto out; |
1499 | } | 1499 | } |
1500 | ret = strict_strtoull(arg_p, 0, &tmp_ll); | 1500 | ret = strict_strtoull(arg_p, 0, &tmp_ll); |
1501 | if (ret < 0) { | 1501 | if (ret < 0) { |
1502 | pr_err("strict_strtoull() failed for" | 1502 | pr_err("strict_strtoull() failed for" |
1503 | " sa_res_key=\n"); | 1503 | " sa_res_key=\n"); |
1504 | goto out; | 1504 | goto out; |
1505 | } | 1505 | } |
1506 | sa_res_key = (u64)tmp_ll; | 1506 | sa_res_key = (u64)tmp_ll; |
1507 | break; | 1507 | break; |
1508 | /* | 1508 | /* |
1509 | * PR APTPL Metadata for Reservation | 1509 | * PR APTPL Metadata for Reservation |
1510 | */ | 1510 | */ |
1511 | case Opt_res_holder: | 1511 | case Opt_res_holder: |
1512 | match_int(args, &arg); | 1512 | match_int(args, &arg); |
1513 | res_holder = arg; | 1513 | res_holder = arg; |
1514 | break; | 1514 | break; |
1515 | case Opt_res_type: | 1515 | case Opt_res_type: |
1516 | match_int(args, &arg); | 1516 | match_int(args, &arg); |
1517 | type = (u8)arg; | 1517 | type = (u8)arg; |
1518 | break; | 1518 | break; |
1519 | case Opt_res_scope: | 1519 | case Opt_res_scope: |
1520 | match_int(args, &arg); | 1520 | match_int(args, &arg); |
1521 | scope = (u8)arg; | 1521 | scope = (u8)arg; |
1522 | break; | 1522 | break; |
1523 | case Opt_res_all_tg_pt: | 1523 | case Opt_res_all_tg_pt: |
1524 | match_int(args, &arg); | 1524 | match_int(args, &arg); |
1525 | all_tg_pt = (int)arg; | 1525 | all_tg_pt = (int)arg; |
1526 | break; | 1526 | break; |
1527 | case Opt_mapped_lun: | 1527 | case Opt_mapped_lun: |
1528 | match_int(args, &arg); | 1528 | match_int(args, &arg); |
1529 | mapped_lun = (u32)arg; | 1529 | mapped_lun = (u32)arg; |
1530 | break; | 1530 | break; |
1531 | /* | 1531 | /* |
1532 | * PR APTPL Metadata for Target Port | 1532 | * PR APTPL Metadata for Target Port |
1533 | */ | 1533 | */ |
1534 | case Opt_target_fabric: | 1534 | case Opt_target_fabric: |
1535 | t_fabric = match_strdup(&args[0]); | 1535 | t_fabric = match_strdup(&args[0]); |
1536 | if (!t_fabric) { | 1536 | if (!t_fabric) { |
1537 | ret = -ENOMEM; | 1537 | ret = -ENOMEM; |
1538 | goto out; | 1538 | goto out; |
1539 | } | 1539 | } |
1540 | break; | 1540 | break; |
1541 | case Opt_target_node: | 1541 | case Opt_target_node: |
1542 | t_port = match_strdup(&args[0]); | 1542 | t_port = match_strdup(&args[0]); |
1543 | if (!t_port) { | 1543 | if (!t_port) { |
1544 | ret = -ENOMEM; | 1544 | ret = -ENOMEM; |
1545 | goto out; | 1545 | goto out; |
1546 | } | 1546 | } |
1547 | if (strlen(t_port) >= PR_APTPL_MAX_TPORT_LEN) { | 1547 | if (strlen(t_port) >= PR_APTPL_MAX_TPORT_LEN) { |
1548 | pr_err("APTPL metadata target_node=" | 1548 | pr_err("APTPL metadata target_node=" |
1549 | " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", | 1549 | " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", |
1550 | PR_APTPL_MAX_TPORT_LEN); | 1550 | PR_APTPL_MAX_TPORT_LEN); |
1551 | ret = -EINVAL; | 1551 | ret = -EINVAL; |
1552 | break; | 1552 | break; |
1553 | } | 1553 | } |
1554 | break; | 1554 | break; |
1555 | case Opt_tpgt: | 1555 | case Opt_tpgt: |
1556 | match_int(args, &arg); | 1556 | match_int(args, &arg); |
1557 | tpgt = (u16)arg; | 1557 | tpgt = (u16)arg; |
1558 | break; | 1558 | break; |
1559 | case Opt_port_rtpi: | 1559 | case Opt_port_rtpi: |
1560 | match_int(args, &arg); | 1560 | match_int(args, &arg); |
1561 | port_rpti = (u16)arg; | 1561 | port_rpti = (u16)arg; |
1562 | break; | 1562 | break; |
1563 | case Opt_target_lun: | 1563 | case Opt_target_lun: |
1564 | match_int(args, &arg); | 1564 | match_int(args, &arg); |
1565 | target_lun = (u32)arg; | 1565 | target_lun = (u32)arg; |
1566 | break; | 1566 | break; |
1567 | default: | 1567 | default: |
1568 | break; | 1568 | break; |
1569 | } | 1569 | } |
1570 | } | 1570 | } |
1571 | 1571 | ||
1572 | if (!i_port || !t_port || !sa_res_key) { | 1572 | if (!i_port || !t_port || !sa_res_key) { |
1573 | pr_err("Illegal parameters for APTPL registration\n"); | 1573 | pr_err("Illegal parameters for APTPL registration\n"); |
1574 | ret = -EINVAL; | 1574 | ret = -EINVAL; |
1575 | goto out; | 1575 | goto out; |
1576 | } | 1576 | } |
1577 | 1577 | ||
1578 | if (res_holder && !(type)) { | 1578 | if (res_holder && !(type)) { |
1579 | pr_err("Illegal PR type: 0x%02x for reservation" | 1579 | pr_err("Illegal PR type: 0x%02x for reservation" |
1580 | " holder\n", type); | 1580 | " holder\n", type); |
1581 | ret = -EINVAL; | 1581 | ret = -EINVAL; |
1582 | goto out; | 1582 | goto out; |
1583 | } | 1583 | } |
1584 | 1584 | ||
1585 | ret = core_scsi3_alloc_aptpl_registration(&su_dev->t10_pr, sa_res_key, | 1585 | ret = core_scsi3_alloc_aptpl_registration(&su_dev->t10_pr, sa_res_key, |
1586 | i_port, isid, mapped_lun, t_port, tpgt, target_lun, | 1586 | i_port, isid, mapped_lun, t_port, tpgt, target_lun, |
1587 | res_holder, all_tg_pt, type); | 1587 | res_holder, all_tg_pt, type); |
1588 | out: | 1588 | out: |
1589 | kfree(i_fabric); | 1589 | kfree(i_fabric); |
1590 | kfree(i_port); | 1590 | kfree(i_port); |
1591 | kfree(isid); | 1591 | kfree(isid); |
1592 | kfree(t_fabric); | 1592 | kfree(t_fabric); |
1593 | kfree(t_port); | 1593 | kfree(t_port); |
1594 | kfree(orig); | 1594 | kfree(orig); |
1595 | return (ret == 0) ? count : ret; | 1595 | return (ret == 0) ? count : ret; |
1596 | } | 1596 | } |
1597 | 1597 | ||
1598 | SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR); | 1598 | SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR); |
1599 | 1599 | ||
1600 | CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group); | 1600 | CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group); |
1601 | 1601 | ||
1602 | static struct configfs_attribute *target_core_dev_pr_attrs[] = { | 1602 | static struct configfs_attribute *target_core_dev_pr_attrs[] = { |
1603 | &target_core_dev_pr_res_holder.attr, | 1603 | &target_core_dev_pr_res_holder.attr, |
1604 | &target_core_dev_pr_res_pr_all_tgt_pts.attr, | 1604 | &target_core_dev_pr_res_pr_all_tgt_pts.attr, |
1605 | &target_core_dev_pr_res_pr_generation.attr, | 1605 | &target_core_dev_pr_res_pr_generation.attr, |
1606 | &target_core_dev_pr_res_pr_holder_tg_port.attr, | 1606 | &target_core_dev_pr_res_pr_holder_tg_port.attr, |
1607 | &target_core_dev_pr_res_pr_registered_i_pts.attr, | 1607 | &target_core_dev_pr_res_pr_registered_i_pts.attr, |
1608 | &target_core_dev_pr_res_pr_type.attr, | 1608 | &target_core_dev_pr_res_pr_type.attr, |
1609 | &target_core_dev_pr_res_type.attr, | 1609 | &target_core_dev_pr_res_type.attr, |
1610 | &target_core_dev_pr_res_aptpl_active.attr, | 1610 | &target_core_dev_pr_res_aptpl_active.attr, |
1611 | &target_core_dev_pr_res_aptpl_metadata.attr, | 1611 | &target_core_dev_pr_res_aptpl_metadata.attr, |
1612 | NULL, | 1612 | NULL, |
1613 | }; | 1613 | }; |
1614 | 1614 | ||
1615 | static struct configfs_item_operations target_core_dev_pr_ops = { | 1615 | static struct configfs_item_operations target_core_dev_pr_ops = { |
1616 | .show_attribute = target_core_dev_pr_attr_show, | 1616 | .show_attribute = target_core_dev_pr_attr_show, |
1617 | .store_attribute = target_core_dev_pr_attr_store, | 1617 | .store_attribute = target_core_dev_pr_attr_store, |
1618 | }; | 1618 | }; |
1619 | 1619 | ||
1620 | static struct config_item_type target_core_dev_pr_cit = { | 1620 | static struct config_item_type target_core_dev_pr_cit = { |
1621 | .ct_item_ops = &target_core_dev_pr_ops, | 1621 | .ct_item_ops = &target_core_dev_pr_ops, |
1622 | .ct_attrs = target_core_dev_pr_attrs, | 1622 | .ct_attrs = target_core_dev_pr_attrs, |
1623 | .ct_owner = THIS_MODULE, | 1623 | .ct_owner = THIS_MODULE, |
1624 | }; | 1624 | }; |
1625 | 1625 | ||
1626 | /* End functions for struct config_item_type target_core_dev_pr_cit */ | 1626 | /* End functions for struct config_item_type target_core_dev_pr_cit */ |
1627 | 1627 | ||
1628 | /* Start functions for struct config_item_type target_core_dev_cit */ | 1628 | /* Start functions for struct config_item_type target_core_dev_cit */ |
1629 | 1629 | ||
1630 | static ssize_t target_core_show_dev_info(void *p, char *page) | 1630 | static ssize_t target_core_show_dev_info(void *p, char *page) |
1631 | { | 1631 | { |
1632 | struct se_subsystem_dev *se_dev = p; | 1632 | struct se_subsystem_dev *se_dev = p; |
1633 | struct se_hba *hba = se_dev->se_dev_hba; | 1633 | struct se_hba *hba = se_dev->se_dev_hba; |
1634 | struct se_subsystem_api *t = hba->transport; | 1634 | struct se_subsystem_api *t = hba->transport; |
1635 | int bl = 0; | 1635 | int bl = 0; |
1636 | ssize_t read_bytes = 0; | 1636 | ssize_t read_bytes = 0; |
1637 | 1637 | ||
1638 | if (!se_dev->se_dev_ptr) | 1638 | if (!se_dev->se_dev_ptr) |
1639 | return -ENODEV; | 1639 | return -ENODEV; |
1640 | 1640 | ||
1641 | transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl); | 1641 | transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl); |
1642 | read_bytes += bl; | 1642 | read_bytes += bl; |
1643 | read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes); | 1643 | read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes); |
1644 | return read_bytes; | 1644 | return read_bytes; |
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | static struct target_core_configfs_attribute target_core_attr_dev_info = { | 1647 | static struct target_core_configfs_attribute target_core_attr_dev_info = { |
1648 | .attr = { .ca_owner = THIS_MODULE, | 1648 | .attr = { .ca_owner = THIS_MODULE, |
1649 | .ca_name = "info", | 1649 | .ca_name = "info", |
1650 | .ca_mode = S_IRUGO }, | 1650 | .ca_mode = S_IRUGO }, |
1651 | .show = target_core_show_dev_info, | 1651 | .show = target_core_show_dev_info, |
1652 | .store = NULL, | 1652 | .store = NULL, |
1653 | }; | 1653 | }; |
1654 | 1654 | ||
1655 | static ssize_t target_core_store_dev_control( | 1655 | static ssize_t target_core_store_dev_control( |
1656 | void *p, | 1656 | void *p, |
1657 | const char *page, | 1657 | const char *page, |
1658 | size_t count) | 1658 | size_t count) |
1659 | { | 1659 | { |
1660 | struct se_subsystem_dev *se_dev = p; | 1660 | struct se_subsystem_dev *se_dev = p; |
1661 | struct se_hba *hba = se_dev->se_dev_hba; | 1661 | struct se_hba *hba = se_dev->se_dev_hba; |
1662 | struct se_subsystem_api *t = hba->transport; | 1662 | struct se_subsystem_api *t = hba->transport; |
1663 | 1663 | ||
1664 | if (!se_dev->se_dev_su_ptr) { | 1664 | if (!se_dev->se_dev_su_ptr) { |
1665 | pr_err("Unable to locate struct se_subsystem_dev>se" | 1665 | pr_err("Unable to locate struct se_subsystem_dev>se" |
1666 | "_dev_su_ptr\n"); | 1666 | "_dev_su_ptr\n"); |
1667 | return -EINVAL; | 1667 | return -EINVAL; |
1668 | } | 1668 | } |
1669 | 1669 | ||
1670 | return t->set_configfs_dev_params(hba, se_dev, page, count); | 1670 | return t->set_configfs_dev_params(hba, se_dev, page, count); |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | static struct target_core_configfs_attribute target_core_attr_dev_control = { | 1673 | static struct target_core_configfs_attribute target_core_attr_dev_control = { |
1674 | .attr = { .ca_owner = THIS_MODULE, | 1674 | .attr = { .ca_owner = THIS_MODULE, |
1675 | .ca_name = "control", | 1675 | .ca_name = "control", |
1676 | .ca_mode = S_IWUSR }, | 1676 | .ca_mode = S_IWUSR }, |
1677 | .show = NULL, | 1677 | .show = NULL, |
1678 | .store = target_core_store_dev_control, | 1678 | .store = target_core_store_dev_control, |
1679 | }; | 1679 | }; |
1680 | 1680 | ||
1681 | static ssize_t target_core_show_dev_alias(void *p, char *page) | 1681 | static ssize_t target_core_show_dev_alias(void *p, char *page) |
1682 | { | 1682 | { |
1683 | struct se_subsystem_dev *se_dev = p; | 1683 | struct se_subsystem_dev *se_dev = p; |
1684 | 1684 | ||
1685 | if (!(se_dev->su_dev_flags & SDF_USING_ALIAS)) | 1685 | if (!(se_dev->su_dev_flags & SDF_USING_ALIAS)) |
1686 | return 0; | 1686 | return 0; |
1687 | 1687 | ||
1688 | return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias); | 1688 | return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias); |
1689 | } | 1689 | } |
1690 | 1690 | ||
1691 | static ssize_t target_core_store_dev_alias( | 1691 | static ssize_t target_core_store_dev_alias( |
1692 | void *p, | 1692 | void *p, |
1693 | const char *page, | 1693 | const char *page, |
1694 | size_t count) | 1694 | size_t count) |
1695 | { | 1695 | { |
1696 | struct se_subsystem_dev *se_dev = p; | 1696 | struct se_subsystem_dev *se_dev = p; |
1697 | struct se_hba *hba = se_dev->se_dev_hba; | 1697 | struct se_hba *hba = se_dev->se_dev_hba; |
1698 | ssize_t read_bytes; | 1698 | ssize_t read_bytes; |
1699 | 1699 | ||
1700 | if (count > (SE_DEV_ALIAS_LEN-1)) { | 1700 | if (count > (SE_DEV_ALIAS_LEN-1)) { |
1701 | pr_err("alias count: %d exceeds" | 1701 | pr_err("alias count: %d exceeds" |
1702 | " SE_DEV_ALIAS_LEN-1: %u\n", (int)count, | 1702 | " SE_DEV_ALIAS_LEN-1: %u\n", (int)count, |
1703 | SE_DEV_ALIAS_LEN-1); | 1703 | SE_DEV_ALIAS_LEN-1); |
1704 | return -EINVAL; | 1704 | return -EINVAL; |
1705 | } | 1705 | } |
1706 | 1706 | ||
1707 | read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, | 1707 | read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, |
1708 | "%s", page); | 1708 | "%s", page); |
1709 | if (!read_bytes) | 1709 | if (!read_bytes) |
1710 | return -EINVAL; | 1710 | return -EINVAL; |
1711 | if (se_dev->se_dev_alias[read_bytes - 1] == '\n') | 1711 | if (se_dev->se_dev_alias[read_bytes - 1] == '\n') |
1712 | se_dev->se_dev_alias[read_bytes - 1] = '\0'; | 1712 | se_dev->se_dev_alias[read_bytes - 1] = '\0'; |
1713 | 1713 | ||
1714 | se_dev->su_dev_flags |= SDF_USING_ALIAS; | 1714 | se_dev->su_dev_flags |= SDF_USING_ALIAS; |
1715 | 1715 | ||
1716 | pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n", | 1716 | pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n", |
1717 | config_item_name(&hba->hba_group.cg_item), | 1717 | config_item_name(&hba->hba_group.cg_item), |
1718 | config_item_name(&se_dev->se_dev_group.cg_item), | 1718 | config_item_name(&se_dev->se_dev_group.cg_item), |
1719 | se_dev->se_dev_alias); | 1719 | se_dev->se_dev_alias); |
1720 | 1720 | ||
1721 | return read_bytes; | 1721 | return read_bytes; |
1722 | } | 1722 | } |
1723 | 1723 | ||
1724 | static struct target_core_configfs_attribute target_core_attr_dev_alias = { | 1724 | static struct target_core_configfs_attribute target_core_attr_dev_alias = { |
1725 | .attr = { .ca_owner = THIS_MODULE, | 1725 | .attr = { .ca_owner = THIS_MODULE, |
1726 | .ca_name = "alias", | 1726 | .ca_name = "alias", |
1727 | .ca_mode = S_IRUGO | S_IWUSR }, | 1727 | .ca_mode = S_IRUGO | S_IWUSR }, |
1728 | .show = target_core_show_dev_alias, | 1728 | .show = target_core_show_dev_alias, |
1729 | .store = target_core_store_dev_alias, | 1729 | .store = target_core_store_dev_alias, |
1730 | }; | 1730 | }; |
1731 | 1731 | ||
1732 | static ssize_t target_core_show_dev_udev_path(void *p, char *page) | 1732 | static ssize_t target_core_show_dev_udev_path(void *p, char *page) |
1733 | { | 1733 | { |
1734 | struct se_subsystem_dev *se_dev = p; | 1734 | struct se_subsystem_dev *se_dev = p; |
1735 | 1735 | ||
1736 | if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) | 1736 | if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) |
1737 | return 0; | 1737 | return 0; |
1738 | 1738 | ||
1739 | return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path); | 1739 | return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path); |
1740 | } | 1740 | } |
1741 | 1741 | ||
1742 | static ssize_t target_core_store_dev_udev_path( | 1742 | static ssize_t target_core_store_dev_udev_path( |
1743 | void *p, | 1743 | void *p, |
1744 | const char *page, | 1744 | const char *page, |
1745 | size_t count) | 1745 | size_t count) |
1746 | { | 1746 | { |
1747 | struct se_subsystem_dev *se_dev = p; | 1747 | struct se_subsystem_dev *se_dev = p; |
1748 | struct se_hba *hba = se_dev->se_dev_hba; | 1748 | struct se_hba *hba = se_dev->se_dev_hba; |
1749 | ssize_t read_bytes; | 1749 | ssize_t read_bytes; |
1750 | 1750 | ||
1751 | if (count > (SE_UDEV_PATH_LEN-1)) { | 1751 | if (count > (SE_UDEV_PATH_LEN-1)) { |
1752 | pr_err("udev_path count: %d exceeds" | 1752 | pr_err("udev_path count: %d exceeds" |
1753 | " SE_UDEV_PATH_LEN-1: %u\n", (int)count, | 1753 | " SE_UDEV_PATH_LEN-1: %u\n", (int)count, |
1754 | SE_UDEV_PATH_LEN-1); | 1754 | SE_UDEV_PATH_LEN-1); |
1755 | return -EINVAL; | 1755 | return -EINVAL; |
1756 | } | 1756 | } |
1757 | 1757 | ||
1758 | read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, | 1758 | read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, |
1759 | "%s", page); | 1759 | "%s", page); |
1760 | if (!read_bytes) | 1760 | if (!read_bytes) |
1761 | return -EINVAL; | 1761 | return -EINVAL; |
1762 | if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n') | 1762 | if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n') |
1763 | se_dev->se_dev_udev_path[read_bytes - 1] = '\0'; | 1763 | se_dev->se_dev_udev_path[read_bytes - 1] = '\0'; |
1764 | 1764 | ||
1765 | se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; | 1765 | se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; |
1766 | 1766 | ||
1767 | pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n", | 1767 | pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n", |
1768 | config_item_name(&hba->hba_group.cg_item), | 1768 | config_item_name(&hba->hba_group.cg_item), |
1769 | config_item_name(&se_dev->se_dev_group.cg_item), | 1769 | config_item_name(&se_dev->se_dev_group.cg_item), |
1770 | se_dev->se_dev_udev_path); | 1770 | se_dev->se_dev_udev_path); |
1771 | 1771 | ||
1772 | return read_bytes; | 1772 | return read_bytes; |
1773 | } | 1773 | } |
1774 | 1774 | ||
1775 | static struct target_core_configfs_attribute target_core_attr_dev_udev_path = { | 1775 | static struct target_core_configfs_attribute target_core_attr_dev_udev_path = { |
1776 | .attr = { .ca_owner = THIS_MODULE, | 1776 | .attr = { .ca_owner = THIS_MODULE, |
1777 | .ca_name = "udev_path", | 1777 | .ca_name = "udev_path", |
1778 | .ca_mode = S_IRUGO | S_IWUSR }, | 1778 | .ca_mode = S_IRUGO | S_IWUSR }, |
1779 | .show = target_core_show_dev_udev_path, | 1779 | .show = target_core_show_dev_udev_path, |
1780 | .store = target_core_store_dev_udev_path, | 1780 | .store = target_core_store_dev_udev_path, |
1781 | }; | 1781 | }; |
1782 | 1782 | ||
1783 | static ssize_t target_core_store_dev_enable( | 1783 | static ssize_t target_core_store_dev_enable( |
1784 | void *p, | 1784 | void *p, |
1785 | const char *page, | 1785 | const char *page, |
1786 | size_t count) | 1786 | size_t count) |
1787 | { | 1787 | { |
1788 | struct se_subsystem_dev *se_dev = p; | 1788 | struct se_subsystem_dev *se_dev = p; |
1789 | struct se_device *dev; | 1789 | struct se_device *dev; |
1790 | struct se_hba *hba = se_dev->se_dev_hba; | 1790 | struct se_hba *hba = se_dev->se_dev_hba; |
1791 | struct se_subsystem_api *t = hba->transport; | 1791 | struct se_subsystem_api *t = hba->transport; |
1792 | char *ptr; | 1792 | char *ptr; |
1793 | 1793 | ||
1794 | ptr = strstr(page, "1"); | 1794 | ptr = strstr(page, "1"); |
1795 | if (!ptr) { | 1795 | if (!ptr) { |
1796 | pr_err("For dev_enable ops, only valid value" | 1796 | pr_err("For dev_enable ops, only valid value" |
1797 | " is \"1\"\n"); | 1797 | " is \"1\"\n"); |
1798 | return -EINVAL; | 1798 | return -EINVAL; |
1799 | } | 1799 | } |
1800 | if (se_dev->se_dev_ptr) { | 1800 | if (se_dev->se_dev_ptr) { |
1801 | pr_err("se_dev->se_dev_ptr already set for storage" | 1801 | pr_err("se_dev->se_dev_ptr already set for storage" |
1802 | " object\n"); | 1802 | " object\n"); |
1803 | return -EEXIST; | 1803 | return -EEXIST; |
1804 | } | 1804 | } |
1805 | 1805 | ||
1806 | if (t->check_configfs_dev_params(hba, se_dev) < 0) | 1806 | if (t->check_configfs_dev_params(hba, se_dev) < 0) |
1807 | return -EINVAL; | 1807 | return -EINVAL; |
1808 | 1808 | ||
1809 | dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); | 1809 | dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); |
1810 | if (IS_ERR(dev)) | 1810 | if (IS_ERR(dev)) |
1811 | return PTR_ERR(dev); | 1811 | return PTR_ERR(dev); |
1812 | else if (!dev) | 1812 | else if (!dev) |
1813 | return -EINVAL; | 1813 | return -EINVAL; |
1814 | 1814 | ||
1815 | se_dev->se_dev_ptr = dev; | 1815 | se_dev->se_dev_ptr = dev; |
1816 | pr_debug("Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:" | 1816 | pr_debug("Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:" |
1817 | " %p\n", se_dev->se_dev_ptr); | 1817 | " %p\n", se_dev->se_dev_ptr); |
1818 | 1818 | ||
1819 | return count; | 1819 | return count; |
1820 | } | 1820 | } |
1821 | 1821 | ||
1822 | static struct target_core_configfs_attribute target_core_attr_dev_enable = { | 1822 | static struct target_core_configfs_attribute target_core_attr_dev_enable = { |
1823 | .attr = { .ca_owner = THIS_MODULE, | 1823 | .attr = { .ca_owner = THIS_MODULE, |
1824 | .ca_name = "enable", | 1824 | .ca_name = "enable", |
1825 | .ca_mode = S_IWUSR }, | 1825 | .ca_mode = S_IWUSR }, |
1826 | .show = NULL, | 1826 | .show = NULL, |
1827 | .store = target_core_store_dev_enable, | 1827 | .store = target_core_store_dev_enable, |
1828 | }; | 1828 | }; |
1829 | 1829 | ||
1830 | static ssize_t target_core_show_alua_lu_gp(void *p, char *page) | 1830 | static ssize_t target_core_show_alua_lu_gp(void *p, char *page) |
1831 | { | 1831 | { |
1832 | struct se_device *dev; | 1832 | struct se_device *dev; |
1833 | struct se_subsystem_dev *su_dev = p; | 1833 | struct se_subsystem_dev *su_dev = p; |
1834 | struct config_item *lu_ci; | 1834 | struct config_item *lu_ci; |
1835 | struct t10_alua_lu_gp *lu_gp; | 1835 | struct t10_alua_lu_gp *lu_gp; |
1836 | struct t10_alua_lu_gp_member *lu_gp_mem; | 1836 | struct t10_alua_lu_gp_member *lu_gp_mem; |
1837 | ssize_t len = 0; | 1837 | ssize_t len = 0; |
1838 | 1838 | ||
1839 | dev = su_dev->se_dev_ptr; | 1839 | dev = su_dev->se_dev_ptr; |
1840 | if (!dev) | 1840 | if (!dev) |
1841 | return -ENODEV; | 1841 | return -ENODEV; |
1842 | 1842 | ||
1843 | if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) | 1843 | if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) |
1844 | return len; | 1844 | return len; |
1845 | 1845 | ||
1846 | lu_gp_mem = dev->dev_alua_lu_gp_mem; | 1846 | lu_gp_mem = dev->dev_alua_lu_gp_mem; |
1847 | if (!lu_gp_mem) { | 1847 | if (!lu_gp_mem) { |
1848 | pr_err("NULL struct se_device->dev_alua_lu_gp_mem" | 1848 | pr_err("NULL struct se_device->dev_alua_lu_gp_mem" |
1849 | " pointer\n"); | 1849 | " pointer\n"); |
1850 | return -EINVAL; | 1850 | return -EINVAL; |
1851 | } | 1851 | } |
1852 | 1852 | ||
1853 | spin_lock(&lu_gp_mem->lu_gp_mem_lock); | 1853 | spin_lock(&lu_gp_mem->lu_gp_mem_lock); |
1854 | lu_gp = lu_gp_mem->lu_gp; | 1854 | lu_gp = lu_gp_mem->lu_gp; |
1855 | if (lu_gp) { | 1855 | if (lu_gp) { |
1856 | lu_ci = &lu_gp->lu_gp_group.cg_item; | 1856 | lu_ci = &lu_gp->lu_gp_group.cg_item; |
1857 | len += sprintf(page, "LU Group Alias: %s\nLU Group ID: %hu\n", | 1857 | len += sprintf(page, "LU Group Alias: %s\nLU Group ID: %hu\n", |
1858 | config_item_name(lu_ci), lu_gp->lu_gp_id); | 1858 | config_item_name(lu_ci), lu_gp->lu_gp_id); |
1859 | } | 1859 | } |
1860 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); | 1860 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); |
1861 | 1861 | ||
1862 | return len; | 1862 | return len; |
1863 | } | 1863 | } |
1864 | 1864 | ||
1865 | static ssize_t target_core_store_alua_lu_gp( | 1865 | static ssize_t target_core_store_alua_lu_gp( |
1866 | void *p, | 1866 | void *p, |
1867 | const char *page, | 1867 | const char *page, |
1868 | size_t count) | 1868 | size_t count) |
1869 | { | 1869 | { |
1870 | struct se_device *dev; | 1870 | struct se_device *dev; |
1871 | struct se_subsystem_dev *su_dev = p; | 1871 | struct se_subsystem_dev *su_dev = p; |
1872 | struct se_hba *hba = su_dev->se_dev_hba; | 1872 | struct se_hba *hba = su_dev->se_dev_hba; |
1873 | struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL; | 1873 | struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL; |
1874 | struct t10_alua_lu_gp_member *lu_gp_mem; | 1874 | struct t10_alua_lu_gp_member *lu_gp_mem; |
1875 | unsigned char buf[LU_GROUP_NAME_BUF]; | 1875 | unsigned char buf[LU_GROUP_NAME_BUF]; |
1876 | int move = 0; | 1876 | int move = 0; |
1877 | 1877 | ||
1878 | dev = su_dev->se_dev_ptr; | 1878 | dev = su_dev->se_dev_ptr; |
1879 | if (!dev) | 1879 | if (!dev) |
1880 | return -ENODEV; | 1880 | return -ENODEV; |
1881 | 1881 | ||
1882 | if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) { | 1882 | if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) { |
1883 | pr_warn("SPC3_ALUA_EMULATED not enabled for %s/%s\n", | 1883 | pr_warn("SPC3_ALUA_EMULATED not enabled for %s/%s\n", |
1884 | config_item_name(&hba->hba_group.cg_item), | 1884 | config_item_name(&hba->hba_group.cg_item), |
1885 | config_item_name(&su_dev->se_dev_group.cg_item)); | 1885 | config_item_name(&su_dev->se_dev_group.cg_item)); |
1886 | return -EINVAL; | 1886 | return -EINVAL; |
1887 | } | 1887 | } |
1888 | if (count > LU_GROUP_NAME_BUF) { | 1888 | if (count > LU_GROUP_NAME_BUF) { |
1889 | pr_err("ALUA LU Group Alias too large!\n"); | 1889 | pr_err("ALUA LU Group Alias too large!\n"); |
1890 | return -EINVAL; | 1890 | return -EINVAL; |
1891 | } | 1891 | } |
1892 | memset(buf, 0, LU_GROUP_NAME_BUF); | 1892 | memset(buf, 0, LU_GROUP_NAME_BUF); |
1893 | memcpy(buf, page, count); | 1893 | memcpy(buf, page, count); |
1894 | /* | 1894 | /* |
1895 | * Any ALUA logical unit alias besides "NULL" means we will be | 1895 | * Any ALUA logical unit alias besides "NULL" means we will be |
1896 | * making a new group association. | 1896 | * making a new group association. |
1897 | */ | 1897 | */ |
1898 | if (strcmp(strstrip(buf), "NULL")) { | 1898 | if (strcmp(strstrip(buf), "NULL")) { |
1899 | /* | 1899 | /* |
1900 | * core_alua_get_lu_gp_by_name() will increment reference to | 1900 | * core_alua_get_lu_gp_by_name() will increment reference to |
1901 | * struct t10_alua_lu_gp. This reference is released with | 1901 | * struct t10_alua_lu_gp. This reference is released with |
1902 | * core_alua_get_lu_gp_by_name below(). | 1902 | * core_alua_get_lu_gp_by_name below(). |
1903 | */ | 1903 | */ |
1904 | lu_gp_new = core_alua_get_lu_gp_by_name(strstrip(buf)); | 1904 | lu_gp_new = core_alua_get_lu_gp_by_name(strstrip(buf)); |
1905 | if (!lu_gp_new) | 1905 | if (!lu_gp_new) |
1906 | return -ENODEV; | 1906 | return -ENODEV; |
1907 | } | 1907 | } |
1908 | lu_gp_mem = dev->dev_alua_lu_gp_mem; | 1908 | lu_gp_mem = dev->dev_alua_lu_gp_mem; |
1909 | if (!lu_gp_mem) { | 1909 | if (!lu_gp_mem) { |
1910 | if (lu_gp_new) | 1910 | if (lu_gp_new) |
1911 | core_alua_put_lu_gp_from_name(lu_gp_new); | 1911 | core_alua_put_lu_gp_from_name(lu_gp_new); |
1912 | pr_err("NULL struct se_device->dev_alua_lu_gp_mem" | 1912 | pr_err("NULL struct se_device->dev_alua_lu_gp_mem" |
1913 | " pointer\n"); | 1913 | " pointer\n"); |
1914 | return -EINVAL; | 1914 | return -EINVAL; |
1915 | } | 1915 | } |
1916 | 1916 | ||
1917 | spin_lock(&lu_gp_mem->lu_gp_mem_lock); | 1917 | spin_lock(&lu_gp_mem->lu_gp_mem_lock); |
1918 | lu_gp = lu_gp_mem->lu_gp; | 1918 | lu_gp = lu_gp_mem->lu_gp; |
1919 | if (lu_gp) { | 1919 | if (lu_gp) { |
1920 | /* | 1920 | /* |
1921 | * Clearing an existing lu_gp association, and replacing | 1921 | * Clearing an existing lu_gp association, and replacing |
1922 | * with NULL | 1922 | * with NULL |
1923 | */ | 1923 | */ |
1924 | if (!lu_gp_new) { | 1924 | if (!lu_gp_new) { |
1925 | pr_debug("Target_Core_ConfigFS: Releasing %s/%s" | 1925 | pr_debug("Target_Core_ConfigFS: Releasing %s/%s" |
1926 | " from ALUA LU Group: core/alua/lu_gps/%s, ID:" | 1926 | " from ALUA LU Group: core/alua/lu_gps/%s, ID:" |
1927 | " %hu\n", | 1927 | " %hu\n", |
1928 | config_item_name(&hba->hba_group.cg_item), | 1928 | config_item_name(&hba->hba_group.cg_item), |
1929 | config_item_name(&su_dev->se_dev_group.cg_item), | 1929 | config_item_name(&su_dev->se_dev_group.cg_item), |
1930 | config_item_name(&lu_gp->lu_gp_group.cg_item), | 1930 | config_item_name(&lu_gp->lu_gp_group.cg_item), |
1931 | lu_gp->lu_gp_id); | 1931 | lu_gp->lu_gp_id); |
1932 | 1932 | ||
1933 | __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp); | 1933 | __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp); |
1934 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); | 1934 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); |
1935 | 1935 | ||
1936 | return count; | 1936 | return count; |
1937 | } | 1937 | } |
1938 | /* | 1938 | /* |
1939 | * Removing existing association of lu_gp_mem with lu_gp | 1939 | * Removing existing association of lu_gp_mem with lu_gp |
1940 | */ | 1940 | */ |
1941 | __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp); | 1941 | __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp); |
1942 | move = 1; | 1942 | move = 1; |
1943 | } | 1943 | } |
1944 | /* | 1944 | /* |
1945 | * Associate lu_gp_mem with lu_gp_new. | 1945 | * Associate lu_gp_mem with lu_gp_new. |
1946 | */ | 1946 | */ |
1947 | __core_alua_attach_lu_gp_mem(lu_gp_mem, lu_gp_new); | 1947 | __core_alua_attach_lu_gp_mem(lu_gp_mem, lu_gp_new); |
1948 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); | 1948 | spin_unlock(&lu_gp_mem->lu_gp_mem_lock); |
1949 | 1949 | ||
1950 | pr_debug("Target_Core_ConfigFS: %s %s/%s to ALUA LU Group:" | 1950 | pr_debug("Target_Core_ConfigFS: %s %s/%s to ALUA LU Group:" |
1951 | " core/alua/lu_gps/%s, ID: %hu\n", | 1951 | " core/alua/lu_gps/%s, ID: %hu\n", |
1952 | (move) ? "Moving" : "Adding", | 1952 | (move) ? "Moving" : "Adding", |
1953 | config_item_name(&hba->hba_group.cg_item), | 1953 | config_item_name(&hba->hba_group.cg_item), |
1954 | config_item_name(&su_dev->se_dev_group.cg_item), | 1954 | config_item_name(&su_dev->se_dev_group.cg_item), |
1955 | config_item_name(&lu_gp_new->lu_gp_group.cg_item), | 1955 | config_item_name(&lu_gp_new->lu_gp_group.cg_item), |
1956 | lu_gp_new->lu_gp_id); | 1956 | lu_gp_new->lu_gp_id); |
1957 | 1957 | ||
1958 | core_alua_put_lu_gp_from_name(lu_gp_new); | 1958 | core_alua_put_lu_gp_from_name(lu_gp_new); |
1959 | return count; | 1959 | return count; |
1960 | } | 1960 | } |
1961 | 1961 | ||
1962 | static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = { | 1962 | static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = { |
1963 | .attr = { .ca_owner = THIS_MODULE, | 1963 | .attr = { .ca_owner = THIS_MODULE, |
1964 | .ca_name = "alua_lu_gp", | 1964 | .ca_name = "alua_lu_gp", |
1965 | .ca_mode = S_IRUGO | S_IWUSR }, | 1965 | .ca_mode = S_IRUGO | S_IWUSR }, |
1966 | .show = target_core_show_alua_lu_gp, | 1966 | .show = target_core_show_alua_lu_gp, |
1967 | .store = target_core_store_alua_lu_gp, | 1967 | .store = target_core_store_alua_lu_gp, |
1968 | }; | 1968 | }; |
1969 | 1969 | ||
1970 | static struct configfs_attribute *lio_core_dev_attrs[] = { | 1970 | static struct configfs_attribute *lio_core_dev_attrs[] = { |
1971 | &target_core_attr_dev_info.attr, | 1971 | &target_core_attr_dev_info.attr, |
1972 | &target_core_attr_dev_control.attr, | 1972 | &target_core_attr_dev_control.attr, |
1973 | &target_core_attr_dev_alias.attr, | 1973 | &target_core_attr_dev_alias.attr, |
1974 | &target_core_attr_dev_udev_path.attr, | 1974 | &target_core_attr_dev_udev_path.attr, |
1975 | &target_core_attr_dev_enable.attr, | 1975 | &target_core_attr_dev_enable.attr, |
1976 | &target_core_attr_dev_alua_lu_gp.attr, | 1976 | &target_core_attr_dev_alua_lu_gp.attr, |
1977 | NULL, | 1977 | NULL, |
1978 | }; | 1978 | }; |
1979 | 1979 | ||
1980 | static void target_core_dev_release(struct config_item *item) | 1980 | static void target_core_dev_release(struct config_item *item) |
1981 | { | 1981 | { |
1982 | struct se_subsystem_dev *se_dev = container_of(to_config_group(item), | 1982 | struct se_subsystem_dev *se_dev = container_of(to_config_group(item), |
1983 | struct se_subsystem_dev, se_dev_group); | 1983 | struct se_subsystem_dev, se_dev_group); |
1984 | struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); | 1984 | struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); |
1985 | struct se_subsystem_api *t = hba->transport; | 1985 | struct se_subsystem_api *t = hba->transport; |
1986 | struct config_group *dev_cg = &se_dev->se_dev_group; | 1986 | struct config_group *dev_cg = &se_dev->se_dev_group; |
1987 | 1987 | ||
1988 | kfree(dev_cg->default_groups); | 1988 | kfree(dev_cg->default_groups); |
1989 | /* | 1989 | /* |
1990 | * This pointer will set when the storage is enabled with: | 1990 | * This pointer will set when the storage is enabled with: |
1991 | *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` | 1991 | *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` |
1992 | */ | 1992 | */ |
1993 | if (se_dev->se_dev_ptr) { | 1993 | if (se_dev->se_dev_ptr) { |
1994 | pr_debug("Target_Core_ConfigFS: Calling se_free_" | 1994 | pr_debug("Target_Core_ConfigFS: Calling se_free_" |
1995 | "virtual_device() for se_dev_ptr: %p\n", | 1995 | "virtual_device() for se_dev_ptr: %p\n", |
1996 | se_dev->se_dev_ptr); | 1996 | se_dev->se_dev_ptr); |
1997 | 1997 | ||
1998 | se_free_virtual_device(se_dev->se_dev_ptr, hba); | 1998 | se_free_virtual_device(se_dev->se_dev_ptr, hba); |
1999 | } else { | 1999 | } else { |
2000 | /* | 2000 | /* |
2001 | * Release struct se_subsystem_dev->se_dev_su_ptr.. | 2001 | * Release struct se_subsystem_dev->se_dev_su_ptr.. |
2002 | */ | 2002 | */ |
2003 | pr_debug("Target_Core_ConfigFS: Calling t->free_" | 2003 | pr_debug("Target_Core_ConfigFS: Calling t->free_" |
2004 | "device() for se_dev_su_ptr: %p\n", | 2004 | "device() for se_dev_su_ptr: %p\n", |
2005 | se_dev->se_dev_su_ptr); | 2005 | se_dev->se_dev_su_ptr); |
2006 | 2006 | ||
2007 | t->free_device(se_dev->se_dev_su_ptr); | 2007 | t->free_device(se_dev->se_dev_su_ptr); |
2008 | } | 2008 | } |
2009 | 2009 | ||
2010 | pr_debug("Target_Core_ConfigFS: Deallocating se_subsystem" | 2010 | pr_debug("Target_Core_ConfigFS: Deallocating se_subsystem" |
2011 | "_dev_t: %p\n", se_dev); | 2011 | "_dev_t: %p\n", se_dev); |
2012 | kfree(se_dev); | 2012 | kfree(se_dev); |
2013 | } | 2013 | } |
2014 | 2014 | ||
2015 | static ssize_t target_core_dev_show(struct config_item *item, | 2015 | static ssize_t target_core_dev_show(struct config_item *item, |
2016 | struct configfs_attribute *attr, | 2016 | struct configfs_attribute *attr, |
2017 | char *page) | 2017 | char *page) |
2018 | { | 2018 | { |
2019 | struct se_subsystem_dev *se_dev = container_of( | 2019 | struct se_subsystem_dev *se_dev = container_of( |
2020 | to_config_group(item), struct se_subsystem_dev, | 2020 | to_config_group(item), struct se_subsystem_dev, |
2021 | se_dev_group); | 2021 | se_dev_group); |
2022 | struct target_core_configfs_attribute *tc_attr = container_of( | 2022 | struct target_core_configfs_attribute *tc_attr = container_of( |
2023 | attr, struct target_core_configfs_attribute, attr); | 2023 | attr, struct target_core_configfs_attribute, attr); |
2024 | 2024 | ||
2025 | if (!tc_attr->show) | 2025 | if (!tc_attr->show) |
2026 | return -EINVAL; | 2026 | return -EINVAL; |
2027 | 2027 | ||
2028 | return tc_attr->show(se_dev, page); | 2028 | return tc_attr->show(se_dev, page); |
2029 | } | 2029 | } |
2030 | 2030 | ||
2031 | static ssize_t target_core_dev_store(struct config_item *item, | 2031 | static ssize_t target_core_dev_store(struct config_item *item, |
2032 | struct configfs_attribute *attr, | 2032 | struct configfs_attribute *attr, |
2033 | const char *page, size_t count) | 2033 | const char *page, size_t count) |
2034 | { | 2034 | { |
2035 | struct se_subsystem_dev *se_dev = container_of( | 2035 | struct se_subsystem_dev *se_dev = container_of( |
2036 | to_config_group(item), struct se_subsystem_dev, | 2036 | to_config_group(item), struct se_subsystem_dev, |
2037 | se_dev_group); | 2037 | se_dev_group); |
2038 | struct target_core_configfs_attribute *tc_attr = container_of( | 2038 | struct target_core_configfs_attribute *tc_attr = container_of( |
2039 | attr, struct target_core_configfs_attribute, attr); | 2039 | attr, struct target_core_configfs_attribute, attr); |
2040 | 2040 | ||
2041 | if (!tc_attr->store) | 2041 | if (!tc_attr->store) |
2042 | return -EINVAL; | 2042 | return -EINVAL; |
2043 | 2043 | ||
2044 | return tc_attr->store(se_dev, page, count); | 2044 | return tc_attr->store(se_dev, page, count); |
2045 | } | 2045 | } |
2046 | 2046 | ||
2047 | static struct configfs_item_operations target_core_dev_item_ops = { | 2047 | static struct configfs_item_operations target_core_dev_item_ops = { |
2048 | .release = target_core_dev_release, | 2048 | .release = target_core_dev_release, |
2049 | .show_attribute = target_core_dev_show, | 2049 | .show_attribute = target_core_dev_show, |
2050 | .store_attribute = target_core_dev_store, | 2050 | .store_attribute = target_core_dev_store, |
2051 | }; | 2051 | }; |
2052 | 2052 | ||
2053 | static struct config_item_type target_core_dev_cit = { | 2053 | static struct config_item_type target_core_dev_cit = { |
2054 | .ct_item_ops = &target_core_dev_item_ops, | 2054 | .ct_item_ops = &target_core_dev_item_ops, |
2055 | .ct_attrs = lio_core_dev_attrs, | 2055 | .ct_attrs = lio_core_dev_attrs, |
2056 | .ct_owner = THIS_MODULE, | 2056 | .ct_owner = THIS_MODULE, |
2057 | }; | 2057 | }; |
2058 | 2058 | ||
2059 | /* End functions for struct config_item_type target_core_dev_cit */ | 2059 | /* End functions for struct config_item_type target_core_dev_cit */ |
2060 | 2060 | ||
2061 | /* Start functions for struct config_item_type target_core_alua_lu_gp_cit */ | 2061 | /* Start functions for struct config_item_type target_core_alua_lu_gp_cit */ |
2062 | 2062 | ||
2063 | CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp); | 2063 | CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp); |
2064 | #define SE_DEV_ALUA_LU_ATTR(_name, _mode) \ | 2064 | #define SE_DEV_ALUA_LU_ATTR(_name, _mode) \ |
2065 | static struct target_core_alua_lu_gp_attribute \ | 2065 | static struct target_core_alua_lu_gp_attribute \ |
2066 | target_core_alua_lu_gp_##_name = \ | 2066 | target_core_alua_lu_gp_##_name = \ |
2067 | __CONFIGFS_EATTR(_name, _mode, \ | 2067 | __CONFIGFS_EATTR(_name, _mode, \ |
2068 | target_core_alua_lu_gp_show_attr_##_name, \ | 2068 | target_core_alua_lu_gp_show_attr_##_name, \ |
2069 | target_core_alua_lu_gp_store_attr_##_name); | 2069 | target_core_alua_lu_gp_store_attr_##_name); |
2070 | 2070 | ||
2071 | #define SE_DEV_ALUA_LU_ATTR_RO(_name) \ | 2071 | #define SE_DEV_ALUA_LU_ATTR_RO(_name) \ |
2072 | static struct target_core_alua_lu_gp_attribute \ | 2072 | static struct target_core_alua_lu_gp_attribute \ |
2073 | target_core_alua_lu_gp_##_name = \ | 2073 | target_core_alua_lu_gp_##_name = \ |
2074 | __CONFIGFS_EATTR_RO(_name, \ | 2074 | __CONFIGFS_EATTR_RO(_name, \ |
2075 | target_core_alua_lu_gp_show_attr_##_name); | 2075 | target_core_alua_lu_gp_show_attr_##_name); |
2076 | 2076 | ||
2077 | /* | 2077 | /* |
2078 | * lu_gp_id | 2078 | * lu_gp_id |
2079 | */ | 2079 | */ |
2080 | static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id( | 2080 | static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id( |
2081 | struct t10_alua_lu_gp *lu_gp, | 2081 | struct t10_alua_lu_gp *lu_gp, |
2082 | char *page) | 2082 | char *page) |
2083 | { | 2083 | { |
2084 | if (!lu_gp->lu_gp_valid_id) | 2084 | if (!lu_gp->lu_gp_valid_id) |
2085 | return 0; | 2085 | return 0; |
2086 | 2086 | ||
2087 | return sprintf(page, "%hu\n", lu_gp->lu_gp_id); | 2087 | return sprintf(page, "%hu\n", lu_gp->lu_gp_id); |
2088 | } | 2088 | } |
2089 | 2089 | ||
2090 | static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id( | 2090 | static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id( |
2091 | struct t10_alua_lu_gp *lu_gp, | 2091 | struct t10_alua_lu_gp *lu_gp, |
2092 | const char *page, | 2092 | const char *page, |
2093 | size_t count) | 2093 | size_t count) |
2094 | { | 2094 | { |
2095 | struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group; | 2095 | struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group; |
2096 | unsigned long lu_gp_id; | 2096 | unsigned long lu_gp_id; |
2097 | int ret; | 2097 | int ret; |
2098 | 2098 | ||
2099 | ret = strict_strtoul(page, 0, &lu_gp_id); | 2099 | ret = strict_strtoul(page, 0, &lu_gp_id); |
2100 | if (ret < 0) { | 2100 | if (ret < 0) { |
2101 | pr_err("strict_strtoul() returned %d for" | 2101 | pr_err("strict_strtoul() returned %d for" |
2102 | " lu_gp_id\n", ret); | 2102 | " lu_gp_id\n", ret); |
2103 | return -EINVAL; | 2103 | return -EINVAL; |
2104 | } | 2104 | } |
2105 | if (lu_gp_id > 0x0000ffff) { | 2105 | if (lu_gp_id > 0x0000ffff) { |
2106 | pr_err("ALUA lu_gp_id: %lu exceeds maximum:" | 2106 | pr_err("ALUA lu_gp_id: %lu exceeds maximum:" |
2107 | " 0x0000ffff\n", lu_gp_id); | 2107 | " 0x0000ffff\n", lu_gp_id); |
2108 | return -EINVAL; | 2108 | return -EINVAL; |
2109 | } | 2109 | } |
2110 | 2110 | ||
2111 | ret = core_alua_set_lu_gp_id(lu_gp, (u16)lu_gp_id); | 2111 | ret = core_alua_set_lu_gp_id(lu_gp, (u16)lu_gp_id); |
2112 | if (ret < 0) | 2112 | if (ret < 0) |
2113 | return -EINVAL; | 2113 | return -EINVAL; |
2114 | 2114 | ||
2115 | pr_debug("Target_Core_ConfigFS: Set ALUA Logical Unit" | 2115 | pr_debug("Target_Core_ConfigFS: Set ALUA Logical Unit" |
2116 | " Group: core/alua/lu_gps/%s to ID: %hu\n", | 2116 | " Group: core/alua/lu_gps/%s to ID: %hu\n", |
2117 | config_item_name(&alua_lu_gp_cg->cg_item), | 2117 | config_item_name(&alua_lu_gp_cg->cg_item), |
2118 | lu_gp->lu_gp_id); | 2118 | lu_gp->lu_gp_id); |
2119 | 2119 | ||
2120 | return count; | 2120 | return count; |
2121 | } | 2121 | } |
2122 | 2122 | ||
2123 | SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR); | 2123 | SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR); |
2124 | 2124 | ||
2125 | /* | 2125 | /* |
2126 | * members | 2126 | * members |
2127 | */ | 2127 | */ |
2128 | static ssize_t target_core_alua_lu_gp_show_attr_members( | 2128 | static ssize_t target_core_alua_lu_gp_show_attr_members( |
2129 | struct t10_alua_lu_gp *lu_gp, | 2129 | struct t10_alua_lu_gp *lu_gp, |
2130 | char *page) | 2130 | char *page) |
2131 | { | 2131 | { |
2132 | struct se_device *dev; | 2132 | struct se_device *dev; |
2133 | struct se_hba *hba; | 2133 | struct se_hba *hba; |
2134 | struct se_subsystem_dev *su_dev; | 2134 | struct se_subsystem_dev *su_dev; |
2135 | struct t10_alua_lu_gp_member *lu_gp_mem; | 2135 | struct t10_alua_lu_gp_member *lu_gp_mem; |
2136 | ssize_t len = 0, cur_len; | 2136 | ssize_t len = 0, cur_len; |
2137 | unsigned char buf[LU_GROUP_NAME_BUF]; | 2137 | unsigned char buf[LU_GROUP_NAME_BUF]; |
2138 | 2138 | ||
2139 | memset(buf, 0, LU_GROUP_NAME_BUF); | 2139 | memset(buf, 0, LU_GROUP_NAME_BUF); |
2140 | 2140 | ||
2141 | spin_lock(&lu_gp->lu_gp_lock); | 2141 | spin_lock(&lu_gp->lu_gp_lock); |
2142 | list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) { | 2142 | list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) { |
2143 | dev = lu_gp_mem->lu_gp_mem_dev; | 2143 | dev = lu_gp_mem->lu_gp_mem_dev; |
2144 | su_dev = dev->se_sub_dev; | 2144 | su_dev = dev->se_sub_dev; |
2145 | hba = su_dev->se_dev_hba; | 2145 | hba = su_dev->se_dev_hba; |
2146 | 2146 | ||
2147 | cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n", | 2147 | cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n", |
2148 | config_item_name(&hba->hba_group.cg_item), | 2148 | config_item_name(&hba->hba_group.cg_item), |
2149 | config_item_name(&su_dev->se_dev_group.cg_item)); | 2149 | config_item_name(&su_dev->se_dev_group.cg_item)); |
2150 | cur_len++; /* Extra byte for NULL terminator */ | 2150 | cur_len++; /* Extra byte for NULL terminator */ |
2151 | 2151 | ||
2152 | if ((cur_len + len) > PAGE_SIZE) { | 2152 | if ((cur_len + len) > PAGE_SIZE) { |
2153 | pr_warn("Ran out of lu_gp_show_attr" | 2153 | pr_warn("Ran out of lu_gp_show_attr" |
2154 | "_members buffer\n"); | 2154 | "_members buffer\n"); |
2155 | break; | 2155 | break; |
2156 | } | 2156 | } |
2157 | memcpy(page+len, buf, cur_len); | 2157 | memcpy(page+len, buf, cur_len); |
2158 | len += cur_len; | 2158 | len += cur_len; |
2159 | } | 2159 | } |
2160 | spin_unlock(&lu_gp->lu_gp_lock); | 2160 | spin_unlock(&lu_gp->lu_gp_lock); |
2161 | 2161 | ||
2162 | return len; | 2162 | return len; |
2163 | } | 2163 | } |
2164 | 2164 | ||
2165 | SE_DEV_ALUA_LU_ATTR_RO(members); | 2165 | SE_DEV_ALUA_LU_ATTR_RO(members); |
2166 | 2166 | ||
2167 | CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group); | 2167 | CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group); |
2168 | 2168 | ||
2169 | static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = { | 2169 | static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = { |
2170 | &target_core_alua_lu_gp_lu_gp_id.attr, | 2170 | &target_core_alua_lu_gp_lu_gp_id.attr, |
2171 | &target_core_alua_lu_gp_members.attr, | 2171 | &target_core_alua_lu_gp_members.attr, |
2172 | NULL, | 2172 | NULL, |
2173 | }; | 2173 | }; |
2174 | 2174 | ||
2175 | static void target_core_alua_lu_gp_release(struct config_item *item) | 2175 | static void target_core_alua_lu_gp_release(struct config_item *item) |
2176 | { | 2176 | { |
2177 | struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), | 2177 | struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), |
2178 | struct t10_alua_lu_gp, lu_gp_group); | 2178 | struct t10_alua_lu_gp, lu_gp_group); |
2179 | 2179 | ||
2180 | core_alua_free_lu_gp(lu_gp); | 2180 | core_alua_free_lu_gp(lu_gp); |
2181 | } | 2181 | } |
2182 | 2182 | ||
2183 | static struct configfs_item_operations target_core_alua_lu_gp_ops = { | 2183 | static struct configfs_item_operations target_core_alua_lu_gp_ops = { |
2184 | .release = target_core_alua_lu_gp_release, | 2184 | .release = target_core_alua_lu_gp_release, |
2185 | .show_attribute = target_core_alua_lu_gp_attr_show, | 2185 | .show_attribute = target_core_alua_lu_gp_attr_show, |
2186 | .store_attribute = target_core_alua_lu_gp_attr_store, | 2186 | .store_attribute = target_core_alua_lu_gp_attr_store, |
2187 | }; | 2187 | }; |
2188 | 2188 | ||
2189 | static struct config_item_type target_core_alua_lu_gp_cit = { | 2189 | static struct config_item_type target_core_alua_lu_gp_cit = { |
2190 | .ct_item_ops = &target_core_alua_lu_gp_ops, | 2190 | .ct_item_ops = &target_core_alua_lu_gp_ops, |
2191 | .ct_attrs = target_core_alua_lu_gp_attrs, | 2191 | .ct_attrs = target_core_alua_lu_gp_attrs, |
2192 | .ct_owner = THIS_MODULE, | 2192 | .ct_owner = THIS_MODULE, |
2193 | }; | 2193 | }; |
2194 | 2194 | ||
2195 | /* End functions for struct config_item_type target_core_alua_lu_gp_cit */ | 2195 | /* End functions for struct config_item_type target_core_alua_lu_gp_cit */ |
2196 | 2196 | ||
2197 | /* Start functions for struct config_item_type target_core_alua_lu_gps_cit */ | 2197 | /* Start functions for struct config_item_type target_core_alua_lu_gps_cit */ |
2198 | 2198 | ||
2199 | static struct config_group *target_core_alua_create_lu_gp( | 2199 | static struct config_group *target_core_alua_create_lu_gp( |
2200 | struct config_group *group, | 2200 | struct config_group *group, |
2201 | const char *name) | 2201 | const char *name) |
2202 | { | 2202 | { |
2203 | struct t10_alua_lu_gp *lu_gp; | 2203 | struct t10_alua_lu_gp *lu_gp; |
2204 | struct config_group *alua_lu_gp_cg = NULL; | 2204 | struct config_group *alua_lu_gp_cg = NULL; |
2205 | struct config_item *alua_lu_gp_ci = NULL; | 2205 | struct config_item *alua_lu_gp_ci = NULL; |
2206 | 2206 | ||
2207 | lu_gp = core_alua_allocate_lu_gp(name, 0); | 2207 | lu_gp = core_alua_allocate_lu_gp(name, 0); |
2208 | if (IS_ERR(lu_gp)) | 2208 | if (IS_ERR(lu_gp)) |
2209 | return NULL; | 2209 | return NULL; |
2210 | 2210 | ||
2211 | alua_lu_gp_cg = &lu_gp->lu_gp_group; | 2211 | alua_lu_gp_cg = &lu_gp->lu_gp_group; |
2212 | alua_lu_gp_ci = &alua_lu_gp_cg->cg_item; | 2212 | alua_lu_gp_ci = &alua_lu_gp_cg->cg_item; |
2213 | 2213 | ||
2214 | config_group_init_type_name(alua_lu_gp_cg, name, | 2214 | config_group_init_type_name(alua_lu_gp_cg, name, |
2215 | &target_core_alua_lu_gp_cit); | 2215 | &target_core_alua_lu_gp_cit); |
2216 | 2216 | ||
2217 | pr_debug("Target_Core_ConfigFS: Allocated ALUA Logical Unit" | 2217 | pr_debug("Target_Core_ConfigFS: Allocated ALUA Logical Unit" |
2218 | " Group: core/alua/lu_gps/%s\n", | 2218 | " Group: core/alua/lu_gps/%s\n", |
2219 | config_item_name(alua_lu_gp_ci)); | 2219 | config_item_name(alua_lu_gp_ci)); |
2220 | 2220 | ||
2221 | return alua_lu_gp_cg; | 2221 | return alua_lu_gp_cg; |
2222 | 2222 | ||
2223 | } | 2223 | } |
2224 | 2224 | ||
2225 | static void target_core_alua_drop_lu_gp( | 2225 | static void target_core_alua_drop_lu_gp( |
2226 | struct config_group *group, | 2226 | struct config_group *group, |
2227 | struct config_item *item) | 2227 | struct config_item *item) |
2228 | { | 2228 | { |
2229 | struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), | 2229 | struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), |
2230 | struct t10_alua_lu_gp, lu_gp_group); | 2230 | struct t10_alua_lu_gp, lu_gp_group); |
2231 | 2231 | ||
2232 | pr_debug("Target_Core_ConfigFS: Releasing ALUA Logical Unit" | 2232 | pr_debug("Target_Core_ConfigFS: Releasing ALUA Logical Unit" |
2233 | " Group: core/alua/lu_gps/%s, ID: %hu\n", | 2233 | " Group: core/alua/lu_gps/%s, ID: %hu\n", |
2234 | config_item_name(item), lu_gp->lu_gp_id); | 2234 | config_item_name(item), lu_gp->lu_gp_id); |
2235 | /* | 2235 | /* |
2236 | * core_alua_free_lu_gp() is called from target_core_alua_lu_gp_ops->release() | 2236 | * core_alua_free_lu_gp() is called from target_core_alua_lu_gp_ops->release() |
2237 | * -> target_core_alua_lu_gp_release() | 2237 | * -> target_core_alua_lu_gp_release() |
2238 | */ | 2238 | */ |
2239 | config_item_put(item); | 2239 | config_item_put(item); |
2240 | } | 2240 | } |
2241 | 2241 | ||
2242 | static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { | 2242 | static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { |
2243 | .make_group = &target_core_alua_create_lu_gp, | 2243 | .make_group = &target_core_alua_create_lu_gp, |
2244 | .drop_item = &target_core_alua_drop_lu_gp, | 2244 | .drop_item = &target_core_alua_drop_lu_gp, |
2245 | }; | 2245 | }; |
2246 | 2246 | ||
2247 | static struct config_item_type target_core_alua_lu_gps_cit = { | 2247 | static struct config_item_type target_core_alua_lu_gps_cit = { |
2248 | .ct_item_ops = NULL, | 2248 | .ct_item_ops = NULL, |
2249 | .ct_group_ops = &target_core_alua_lu_gps_group_ops, | 2249 | .ct_group_ops = &target_core_alua_lu_gps_group_ops, |
2250 | .ct_owner = THIS_MODULE, | 2250 | .ct_owner = THIS_MODULE, |
2251 | }; | 2251 | }; |
2252 | 2252 | ||
2253 | /* End functions for struct config_item_type target_core_alua_lu_gps_cit */ | 2253 | /* End functions for struct config_item_type target_core_alua_lu_gps_cit */ |
2254 | 2254 | ||
2255 | /* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ | 2255 | /* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ |
2256 | 2256 | ||
2257 | CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp); | 2257 | CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp); |
2258 | #define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \ | 2258 | #define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \ |
2259 | static struct target_core_alua_tg_pt_gp_attribute \ | 2259 | static struct target_core_alua_tg_pt_gp_attribute \ |
2260 | target_core_alua_tg_pt_gp_##_name = \ | 2260 | target_core_alua_tg_pt_gp_##_name = \ |
2261 | __CONFIGFS_EATTR(_name, _mode, \ | 2261 | __CONFIGFS_EATTR(_name, _mode, \ |
2262 | target_core_alua_tg_pt_gp_show_attr_##_name, \ | 2262 | target_core_alua_tg_pt_gp_show_attr_##_name, \ |
2263 | target_core_alua_tg_pt_gp_store_attr_##_name); | 2263 | target_core_alua_tg_pt_gp_store_attr_##_name); |
2264 | 2264 | ||
2265 | #define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \ | 2265 | #define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \ |
2266 | static struct target_core_alua_tg_pt_gp_attribute \ | 2266 | static struct target_core_alua_tg_pt_gp_attribute \ |
2267 | target_core_alua_tg_pt_gp_##_name = \ | 2267 | target_core_alua_tg_pt_gp_##_name = \ |
2268 | __CONFIGFS_EATTR_RO(_name, \ | 2268 | __CONFIGFS_EATTR_RO(_name, \ |
2269 | target_core_alua_tg_pt_gp_show_attr_##_name); | 2269 | target_core_alua_tg_pt_gp_show_attr_##_name); |
2270 | 2270 | ||
2271 | /* | 2271 | /* |
2272 | * alua_access_state | 2272 | * alua_access_state |
2273 | */ | 2273 | */ |
2274 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state( | 2274 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state( |
2275 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2275 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2276 | char *page) | 2276 | char *page) |
2277 | { | 2277 | { |
2278 | return sprintf(page, "%d\n", | 2278 | return sprintf(page, "%d\n", |
2279 | atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state)); | 2279 | atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state)); |
2280 | } | 2280 | } |
2281 | 2281 | ||
2282 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( | 2282 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( |
2283 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2283 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2284 | const char *page, | 2284 | const char *page, |
2285 | size_t count) | 2285 | size_t count) |
2286 | { | 2286 | { |
2287 | struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; | 2287 | struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; |
2288 | unsigned long tmp; | 2288 | unsigned long tmp; |
2289 | int new_state, ret; | 2289 | int new_state, ret; |
2290 | 2290 | ||
2291 | if (!tg_pt_gp->tg_pt_gp_valid_id) { | 2291 | if (!tg_pt_gp->tg_pt_gp_valid_id) { |
2292 | pr_err("Unable to do implict ALUA on non valid" | 2292 | pr_err("Unable to do implict ALUA on non valid" |
2293 | " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id); | 2293 | " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id); |
2294 | return -EINVAL; | 2294 | return -EINVAL; |
2295 | } | 2295 | } |
2296 | 2296 | ||
2297 | ret = strict_strtoul(page, 0, &tmp); | 2297 | ret = strict_strtoul(page, 0, &tmp); |
2298 | if (ret < 0) { | 2298 | if (ret < 0) { |
2299 | pr_err("Unable to extract new ALUA access state from" | 2299 | pr_err("Unable to extract new ALUA access state from" |
2300 | " %s\n", page); | 2300 | " %s\n", page); |
2301 | return -EINVAL; | 2301 | return -EINVAL; |
2302 | } | 2302 | } |
2303 | new_state = (int)tmp; | 2303 | new_state = (int)tmp; |
2304 | 2304 | ||
2305 | if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) { | 2305 | if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) { |
2306 | pr_err("Unable to process implict configfs ALUA" | 2306 | pr_err("Unable to process implict configfs ALUA" |
2307 | " transition while TPGS_IMPLICT_ALUA is diabled\n"); | 2307 | " transition while TPGS_IMPLICT_ALUA is diabled\n"); |
2308 | return -EINVAL; | 2308 | return -EINVAL; |
2309 | } | 2309 | } |
2310 | 2310 | ||
2311 | ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr, | 2311 | ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr, |
2312 | NULL, NULL, new_state, 0); | 2312 | NULL, NULL, new_state, 0); |
2313 | return (!ret) ? count : -EINVAL; | 2313 | return (!ret) ? count : -EINVAL; |
2314 | } | 2314 | } |
2315 | 2315 | ||
2316 | SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR); | 2316 | SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR); |
2317 | 2317 | ||
2318 | /* | 2318 | /* |
2319 | * alua_access_status | 2319 | * alua_access_status |
2320 | */ | 2320 | */ |
2321 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status( | 2321 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status( |
2322 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2322 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2323 | char *page) | 2323 | char *page) |
2324 | { | 2324 | { |
2325 | return sprintf(page, "%s\n", | 2325 | return sprintf(page, "%s\n", |
2326 | core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status)); | 2326 | core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status)); |
2327 | } | 2327 | } |
2328 | 2328 | ||
2329 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status( | 2329 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status( |
2330 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2330 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2331 | const char *page, | 2331 | const char *page, |
2332 | size_t count) | 2332 | size_t count) |
2333 | { | 2333 | { |
2334 | unsigned long tmp; | 2334 | unsigned long tmp; |
2335 | int new_status, ret; | 2335 | int new_status, ret; |
2336 | 2336 | ||
2337 | if (!tg_pt_gp->tg_pt_gp_valid_id) { | 2337 | if (!tg_pt_gp->tg_pt_gp_valid_id) { |
2338 | pr_err("Unable to do set ALUA access status on non" | 2338 | pr_err("Unable to do set ALUA access status on non" |
2339 | " valid tg_pt_gp ID: %hu\n", | 2339 | " valid tg_pt_gp ID: %hu\n", |
2340 | tg_pt_gp->tg_pt_gp_valid_id); | 2340 | tg_pt_gp->tg_pt_gp_valid_id); |
2341 | return -EINVAL; | 2341 | return -EINVAL; |
2342 | } | 2342 | } |
2343 | 2343 | ||
2344 | ret = strict_strtoul(page, 0, &tmp); | 2344 | ret = strict_strtoul(page, 0, &tmp); |
2345 | if (ret < 0) { | 2345 | if (ret < 0) { |
2346 | pr_err("Unable to extract new ALUA access status" | 2346 | pr_err("Unable to extract new ALUA access status" |
2347 | " from %s\n", page); | 2347 | " from %s\n", page); |
2348 | return -EINVAL; | 2348 | return -EINVAL; |
2349 | } | 2349 | } |
2350 | new_status = (int)tmp; | 2350 | new_status = (int)tmp; |
2351 | 2351 | ||
2352 | if ((new_status != ALUA_STATUS_NONE) && | 2352 | if ((new_status != ALUA_STATUS_NONE) && |
2353 | (new_status != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && | 2353 | (new_status != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && |
2354 | (new_status != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) { | 2354 | (new_status != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) { |
2355 | pr_err("Illegal ALUA access status: 0x%02x\n", | 2355 | pr_err("Illegal ALUA access status: 0x%02x\n", |
2356 | new_status); | 2356 | new_status); |
2357 | return -EINVAL; | 2357 | return -EINVAL; |
2358 | } | 2358 | } |
2359 | 2359 | ||
2360 | tg_pt_gp->tg_pt_gp_alua_access_status = new_status; | 2360 | tg_pt_gp->tg_pt_gp_alua_access_status = new_status; |
2361 | return count; | 2361 | return count; |
2362 | } | 2362 | } |
2363 | 2363 | ||
2364 | SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR); | 2364 | SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR); |
2365 | 2365 | ||
2366 | /* | 2366 | /* |
2367 | * alua_access_type | 2367 | * alua_access_type |
2368 | */ | 2368 | */ |
2369 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type( | 2369 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type( |
2370 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2370 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2371 | char *page) | 2371 | char *page) |
2372 | { | 2372 | { |
2373 | return core_alua_show_access_type(tg_pt_gp, page); | 2373 | return core_alua_show_access_type(tg_pt_gp, page); |
2374 | } | 2374 | } |
2375 | 2375 | ||
2376 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type( | 2376 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type( |
2377 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2377 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2378 | const char *page, | 2378 | const char *page, |
2379 | size_t count) | 2379 | size_t count) |
2380 | { | 2380 | { |
2381 | return core_alua_store_access_type(tg_pt_gp, page, count); | 2381 | return core_alua_store_access_type(tg_pt_gp, page, count); |
2382 | } | 2382 | } |
2383 | 2383 | ||
2384 | SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR); | 2384 | SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR); |
2385 | 2385 | ||
2386 | /* | 2386 | /* |
2387 | * alua_write_metadata | 2387 | * alua_write_metadata |
2388 | */ | 2388 | */ |
2389 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( | 2389 | static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( |
2390 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2390 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2391 | char *page) | 2391 | char *page) |
2392 | { | 2392 | { |
2393 | return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata); | 2393 | return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata); |
2394 | } | 2394 | } |
2395 | 2395 | ||
2396 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata( | 2396 | static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata( |
2397 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2397 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2398 | const char *page, | 2398 | const char *page, |
2399 | size_t count) | 2399 | size_t count) |
2400 | { | 2400 | { |
2401 | unsigned long tmp; | 2401 | unsigned long tmp; |
2402 | int ret; | 2402 | int ret; |
2403 | 2403 | ||
2404 | ret = strict_strtoul(page, 0, &tmp); | 2404 | ret = strict_strtoul(page, 0, &tmp); |
2405 | if (ret < 0) { | 2405 | if (ret < 0) { |
2406 | pr_err("Unable to extract alua_write_metadata\n"); | 2406 | pr_err("Unable to extract alua_write_metadata\n"); |
2407 | return -EINVAL; | 2407 | return -EINVAL; |
2408 | } | 2408 | } |
2409 | 2409 | ||
2410 | if ((tmp != 0) && (tmp != 1)) { | 2410 | if ((tmp != 0) && (tmp != 1)) { |
2411 | pr_err("Illegal value for alua_write_metadata:" | 2411 | pr_err("Illegal value for alua_write_metadata:" |
2412 | " %lu\n", tmp); | 2412 | " %lu\n", tmp); |
2413 | return -EINVAL; | 2413 | return -EINVAL; |
2414 | } | 2414 | } |
2415 | tg_pt_gp->tg_pt_gp_write_metadata = (int)tmp; | 2415 | tg_pt_gp->tg_pt_gp_write_metadata = (int)tmp; |
2416 | 2416 | ||
2417 | return count; | 2417 | return count; |
2418 | } | 2418 | } |
2419 | 2419 | ||
2420 | SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR); | 2420 | SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR); |
2421 | 2421 | ||
2422 | 2422 | ||
2423 | 2423 | ||
2424 | /* | 2424 | /* |
2425 | * nonop_delay_msecs | 2425 | * nonop_delay_msecs |
2426 | */ | 2426 | */ |
2427 | static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs( | 2427 | static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs( |
2428 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2428 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2429 | char *page) | 2429 | char *page) |
2430 | { | 2430 | { |
2431 | return core_alua_show_nonop_delay_msecs(tg_pt_gp, page); | 2431 | return core_alua_show_nonop_delay_msecs(tg_pt_gp, page); |
2432 | 2432 | ||
2433 | } | 2433 | } |
2434 | 2434 | ||
2435 | static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs( | 2435 | static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs( |
2436 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2436 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2437 | const char *page, | 2437 | const char *page, |
2438 | size_t count) | 2438 | size_t count) |
2439 | { | 2439 | { |
2440 | return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count); | 2440 | return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count); |
2441 | } | 2441 | } |
2442 | 2442 | ||
2443 | SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR); | 2443 | SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR); |
2444 | 2444 | ||
2445 | /* | 2445 | /* |
2446 | * trans_delay_msecs | 2446 | * trans_delay_msecs |
2447 | */ | 2447 | */ |
2448 | static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs( | 2448 | static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs( |
2449 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2449 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2450 | char *page) | 2450 | char *page) |
2451 | { | 2451 | { |
2452 | return core_alua_show_trans_delay_msecs(tg_pt_gp, page); | 2452 | return core_alua_show_trans_delay_msecs(tg_pt_gp, page); |
2453 | } | 2453 | } |
2454 | 2454 | ||
2455 | static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs( | 2455 | static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs( |
2456 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2456 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2457 | const char *page, | 2457 | const char *page, |
2458 | size_t count) | 2458 | size_t count) |
2459 | { | 2459 | { |
2460 | return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count); | 2460 | return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count); |
2461 | } | 2461 | } |
2462 | 2462 | ||
2463 | SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR); | 2463 | SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR); |
2464 | 2464 | ||
2465 | /* | 2465 | /* |
2466 | * preferred | 2466 | * preferred |
2467 | */ | 2467 | */ |
2468 | 2468 | ||
2469 | static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred( | 2469 | static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred( |
2470 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2470 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2471 | char *page) | 2471 | char *page) |
2472 | { | 2472 | { |
2473 | return core_alua_show_preferred_bit(tg_pt_gp, page); | 2473 | return core_alua_show_preferred_bit(tg_pt_gp, page); |
2474 | } | 2474 | } |
2475 | 2475 | ||
2476 | static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred( | 2476 | static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred( |
2477 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2477 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2478 | const char *page, | 2478 | const char *page, |
2479 | size_t count) | 2479 | size_t count) |
2480 | { | 2480 | { |
2481 | return core_alua_store_preferred_bit(tg_pt_gp, page, count); | 2481 | return core_alua_store_preferred_bit(tg_pt_gp, page, count); |
2482 | } | 2482 | } |
2483 | 2483 | ||
2484 | SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR); | 2484 | SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR); |
2485 | 2485 | ||
2486 | /* | 2486 | /* |
2487 | * tg_pt_gp_id | 2487 | * tg_pt_gp_id |
2488 | */ | 2488 | */ |
2489 | static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id( | 2489 | static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id( |
2490 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2490 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2491 | char *page) | 2491 | char *page) |
2492 | { | 2492 | { |
2493 | if (!tg_pt_gp->tg_pt_gp_valid_id) | 2493 | if (!tg_pt_gp->tg_pt_gp_valid_id) |
2494 | return 0; | 2494 | return 0; |
2495 | 2495 | ||
2496 | return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id); | 2496 | return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id); |
2497 | } | 2497 | } |
2498 | 2498 | ||
2499 | static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id( | 2499 | static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id( |
2500 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2500 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2501 | const char *page, | 2501 | const char *page, |
2502 | size_t count) | 2502 | size_t count) |
2503 | { | 2503 | { |
2504 | struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; | 2504 | struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; |
2505 | unsigned long tg_pt_gp_id; | 2505 | unsigned long tg_pt_gp_id; |
2506 | int ret; | 2506 | int ret; |
2507 | 2507 | ||
2508 | ret = strict_strtoul(page, 0, &tg_pt_gp_id); | 2508 | ret = strict_strtoul(page, 0, &tg_pt_gp_id); |
2509 | if (ret < 0) { | 2509 | if (ret < 0) { |
2510 | pr_err("strict_strtoul() returned %d for" | 2510 | pr_err("strict_strtoul() returned %d for" |
2511 | " tg_pt_gp_id\n", ret); | 2511 | " tg_pt_gp_id\n", ret); |
2512 | return -EINVAL; | 2512 | return -EINVAL; |
2513 | } | 2513 | } |
2514 | if (tg_pt_gp_id > 0x0000ffff) { | 2514 | if (tg_pt_gp_id > 0x0000ffff) { |
2515 | pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum:" | 2515 | pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum:" |
2516 | " 0x0000ffff\n", tg_pt_gp_id); | 2516 | " 0x0000ffff\n", tg_pt_gp_id); |
2517 | return -EINVAL; | 2517 | return -EINVAL; |
2518 | } | 2518 | } |
2519 | 2519 | ||
2520 | ret = core_alua_set_tg_pt_gp_id(tg_pt_gp, (u16)tg_pt_gp_id); | 2520 | ret = core_alua_set_tg_pt_gp_id(tg_pt_gp, (u16)tg_pt_gp_id); |
2521 | if (ret < 0) | 2521 | if (ret < 0) |
2522 | return -EINVAL; | 2522 | return -EINVAL; |
2523 | 2523 | ||
2524 | pr_debug("Target_Core_ConfigFS: Set ALUA Target Port Group: " | 2524 | pr_debug("Target_Core_ConfigFS: Set ALUA Target Port Group: " |
2525 | "core/alua/tg_pt_gps/%s to ID: %hu\n", | 2525 | "core/alua/tg_pt_gps/%s to ID: %hu\n", |
2526 | config_item_name(&alua_tg_pt_gp_cg->cg_item), | 2526 | config_item_name(&alua_tg_pt_gp_cg->cg_item), |
2527 | tg_pt_gp->tg_pt_gp_id); | 2527 | tg_pt_gp->tg_pt_gp_id); |
2528 | 2528 | ||
2529 | return count; | 2529 | return count; |
2530 | } | 2530 | } |
2531 | 2531 | ||
2532 | SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR); | 2532 | SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR); |
2533 | 2533 | ||
2534 | /* | 2534 | /* |
2535 | * members | 2535 | * members |
2536 | */ | 2536 | */ |
2537 | static ssize_t target_core_alua_tg_pt_gp_show_attr_members( | 2537 | static ssize_t target_core_alua_tg_pt_gp_show_attr_members( |
2538 | struct t10_alua_tg_pt_gp *tg_pt_gp, | 2538 | struct t10_alua_tg_pt_gp *tg_pt_gp, |
2539 | char *page) | 2539 | char *page) |
2540 | { | 2540 | { |
2541 | struct se_port *port; | 2541 | struct se_port *port; |
2542 | struct se_portal_group *tpg; | 2542 | struct se_portal_group *tpg; |
2543 | struct se_lun *lun; | 2543 | struct se_lun *lun; |
2544 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; | 2544 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; |
2545 | ssize_t len = 0, cur_len; | 2545 | ssize_t len = 0, cur_len; |
2546 | unsigned char buf[TG_PT_GROUP_NAME_BUF]; | 2546 | unsigned char buf[TG_PT_GROUP_NAME_BUF]; |
2547 | 2547 | ||
2548 | memset(buf, 0, TG_PT_GROUP_NAME_BUF); | 2548 | memset(buf, 0, TG_PT_GROUP_NAME_BUF); |
2549 | 2549 | ||
2550 | spin_lock(&tg_pt_gp->tg_pt_gp_lock); | 2550 | spin_lock(&tg_pt_gp->tg_pt_gp_lock); |
2551 | list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, | 2551 | list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, |
2552 | tg_pt_gp_mem_list) { | 2552 | tg_pt_gp_mem_list) { |
2553 | port = tg_pt_gp_mem->tg_pt; | 2553 | port = tg_pt_gp_mem->tg_pt; |
2554 | tpg = port->sep_tpg; | 2554 | tpg = port->sep_tpg; |
2555 | lun = port->sep_lun; | 2555 | lun = port->sep_lun; |
2556 | 2556 | ||
2557 | cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu" | 2557 | cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu" |
2558 | "/%s\n", tpg->se_tpg_tfo->get_fabric_name(), | 2558 | "/%s\n", tpg->se_tpg_tfo->get_fabric_name(), |
2559 | tpg->se_tpg_tfo->tpg_get_wwn(tpg), | 2559 | tpg->se_tpg_tfo->tpg_get_wwn(tpg), |
2560 | tpg->se_tpg_tfo->tpg_get_tag(tpg), | 2560 | tpg->se_tpg_tfo->tpg_get_tag(tpg), |
2561 | config_item_name(&lun->lun_group.cg_item)); | 2561 | config_item_name(&lun->lun_group.cg_item)); |
2562 | cur_len++; /* Extra byte for NULL terminator */ | 2562 | cur_len++; /* Extra byte for NULL terminator */ |
2563 | 2563 | ||
2564 | if ((cur_len + len) > PAGE_SIZE) { | 2564 | if ((cur_len + len) > PAGE_SIZE) { |
2565 | pr_warn("Ran out of lu_gp_show_attr" | 2565 | pr_warn("Ran out of lu_gp_show_attr" |
2566 | "_members buffer\n"); | 2566 | "_members buffer\n"); |
2567 | break; | 2567 | break; |
2568 | } | 2568 | } |
2569 | memcpy(page+len, buf, cur_len); | 2569 | memcpy(page+len, buf, cur_len); |
2570 | len += cur_len; | 2570 | len += cur_len; |
2571 | } | 2571 | } |
2572 | spin_unlock(&tg_pt_gp->tg_pt_gp_lock); | 2572 | spin_unlock(&tg_pt_gp->tg_pt_gp_lock); |
2573 | 2573 | ||
2574 | return len; | 2574 | return len; |
2575 | } | 2575 | } |
2576 | 2576 | ||
2577 | SE_DEV_ALUA_TG_PT_ATTR_RO(members); | 2577 | SE_DEV_ALUA_TG_PT_ATTR_RO(members); |
2578 | 2578 | ||
2579 | CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp, | 2579 | CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp, |
2580 | tg_pt_gp_group); | 2580 | tg_pt_gp_group); |
2581 | 2581 | ||
2582 | static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { | 2582 | static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { |
2583 | &target_core_alua_tg_pt_gp_alua_access_state.attr, | 2583 | &target_core_alua_tg_pt_gp_alua_access_state.attr, |
2584 | &target_core_alua_tg_pt_gp_alua_access_status.attr, | 2584 | &target_core_alua_tg_pt_gp_alua_access_status.attr, |
2585 | &target_core_alua_tg_pt_gp_alua_access_type.attr, | 2585 | &target_core_alua_tg_pt_gp_alua_access_type.attr, |
2586 | &target_core_alua_tg_pt_gp_alua_write_metadata.attr, | 2586 | &target_core_alua_tg_pt_gp_alua_write_metadata.attr, |
2587 | &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, | 2587 | &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, |
2588 | &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, | 2588 | &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, |
2589 | &target_core_alua_tg_pt_gp_preferred.attr, | 2589 | &target_core_alua_tg_pt_gp_preferred.attr, |
2590 | &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr, | 2590 | &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr, |
2591 | &target_core_alua_tg_pt_gp_members.attr, | 2591 | &target_core_alua_tg_pt_gp_members.attr, |
2592 | NULL, | 2592 | NULL, |
2593 | }; | 2593 | }; |
2594 | 2594 | ||
2595 | static void target_core_alua_tg_pt_gp_release(struct config_item *item) | 2595 | static void target_core_alua_tg_pt_gp_release(struct config_item *item) |
2596 | { | 2596 | { |
2597 | struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), | 2597 | struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), |
2598 | struct t10_alua_tg_pt_gp, tg_pt_gp_group); | 2598 | struct t10_alua_tg_pt_gp, tg_pt_gp_group); |
2599 | 2599 | ||
2600 | core_alua_free_tg_pt_gp(tg_pt_gp); | 2600 | core_alua_free_tg_pt_gp(tg_pt_gp); |
2601 | } | 2601 | } |
2602 | 2602 | ||
2603 | static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { | 2603 | static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { |
2604 | .release = target_core_alua_tg_pt_gp_release, | 2604 | .release = target_core_alua_tg_pt_gp_release, |
2605 | .show_attribute = target_core_alua_tg_pt_gp_attr_show, | 2605 | .show_attribute = target_core_alua_tg_pt_gp_attr_show, |
2606 | .store_attribute = target_core_alua_tg_pt_gp_attr_store, | 2606 | .store_attribute = target_core_alua_tg_pt_gp_attr_store, |
2607 | }; | 2607 | }; |
2608 | 2608 | ||
2609 | static struct config_item_type target_core_alua_tg_pt_gp_cit = { | 2609 | static struct config_item_type target_core_alua_tg_pt_gp_cit = { |
2610 | .ct_item_ops = &target_core_alua_tg_pt_gp_ops, | 2610 | .ct_item_ops = &target_core_alua_tg_pt_gp_ops, |
2611 | .ct_attrs = target_core_alua_tg_pt_gp_attrs, | 2611 | .ct_attrs = target_core_alua_tg_pt_gp_attrs, |
2612 | .ct_owner = THIS_MODULE, | 2612 | .ct_owner = THIS_MODULE, |
2613 | }; | 2613 | }; |
2614 | 2614 | ||
2615 | /* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ | 2615 | /* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ |
2616 | 2616 | ||
2617 | /* Start functions for struct config_item_type target_core_alua_tg_pt_gps_cit */ | 2617 | /* Start functions for struct config_item_type target_core_alua_tg_pt_gps_cit */ |
2618 | 2618 | ||
2619 | static struct config_group *target_core_alua_create_tg_pt_gp( | 2619 | static struct config_group *target_core_alua_create_tg_pt_gp( |
2620 | struct config_group *group, | 2620 | struct config_group *group, |
2621 | const char *name) | 2621 | const char *name) |
2622 | { | 2622 | { |
2623 | struct t10_alua *alua = container_of(group, struct t10_alua, | 2623 | struct t10_alua *alua = container_of(group, struct t10_alua, |
2624 | alua_tg_pt_gps_group); | 2624 | alua_tg_pt_gps_group); |
2625 | struct t10_alua_tg_pt_gp *tg_pt_gp; | 2625 | struct t10_alua_tg_pt_gp *tg_pt_gp; |
2626 | struct se_subsystem_dev *su_dev = alua->t10_sub_dev; | 2626 | struct se_subsystem_dev *su_dev = alua->t10_sub_dev; |
2627 | struct config_group *alua_tg_pt_gp_cg = NULL; | 2627 | struct config_group *alua_tg_pt_gp_cg = NULL; |
2628 | struct config_item *alua_tg_pt_gp_ci = NULL; | 2628 | struct config_item *alua_tg_pt_gp_ci = NULL; |
2629 | 2629 | ||
2630 | tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0); | 2630 | tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0); |
2631 | if (!tg_pt_gp) | 2631 | if (!tg_pt_gp) |
2632 | return NULL; | 2632 | return NULL; |
2633 | 2633 | ||
2634 | alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; | 2634 | alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; |
2635 | alua_tg_pt_gp_ci = &alua_tg_pt_gp_cg->cg_item; | 2635 | alua_tg_pt_gp_ci = &alua_tg_pt_gp_cg->cg_item; |
2636 | 2636 | ||
2637 | config_group_init_type_name(alua_tg_pt_gp_cg, name, | 2637 | config_group_init_type_name(alua_tg_pt_gp_cg, name, |
2638 | &target_core_alua_tg_pt_gp_cit); | 2638 | &target_core_alua_tg_pt_gp_cit); |
2639 | 2639 | ||
2640 | pr_debug("Target_Core_ConfigFS: Allocated ALUA Target Port" | 2640 | pr_debug("Target_Core_ConfigFS: Allocated ALUA Target Port" |
2641 | " Group: alua/tg_pt_gps/%s\n", | 2641 | " Group: alua/tg_pt_gps/%s\n", |
2642 | config_item_name(alua_tg_pt_gp_ci)); | 2642 | config_item_name(alua_tg_pt_gp_ci)); |
2643 | 2643 | ||
2644 | return alua_tg_pt_gp_cg; | 2644 | return alua_tg_pt_gp_cg; |
2645 | } | 2645 | } |
2646 | 2646 | ||
2647 | static void target_core_alua_drop_tg_pt_gp( | 2647 | static void target_core_alua_drop_tg_pt_gp( |
2648 | struct config_group *group, | 2648 | struct config_group *group, |
2649 | struct config_item *item) | 2649 | struct config_item *item) |
2650 | { | 2650 | { |
2651 | struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), | 2651 | struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), |
2652 | struct t10_alua_tg_pt_gp, tg_pt_gp_group); | 2652 | struct t10_alua_tg_pt_gp, tg_pt_gp_group); |
2653 | 2653 | ||
2654 | pr_debug("Target_Core_ConfigFS: Releasing ALUA Target Port" | 2654 | pr_debug("Target_Core_ConfigFS: Releasing ALUA Target Port" |
2655 | " Group: alua/tg_pt_gps/%s, ID: %hu\n", | 2655 | " Group: alua/tg_pt_gps/%s, ID: %hu\n", |
2656 | config_item_name(item), tg_pt_gp->tg_pt_gp_id); | 2656 | config_item_name(item), tg_pt_gp->tg_pt_gp_id); |
2657 | /* | 2657 | /* |
2658 | * core_alua_free_tg_pt_gp() is called from target_core_alua_tg_pt_gp_ops->release() | 2658 | * core_alua_free_tg_pt_gp() is called from target_core_alua_tg_pt_gp_ops->release() |
2659 | * -> target_core_alua_tg_pt_gp_release(). | 2659 | * -> target_core_alua_tg_pt_gp_release(). |
2660 | */ | 2660 | */ |
2661 | config_item_put(item); | 2661 | config_item_put(item); |
2662 | } | 2662 | } |
2663 | 2663 | ||
2664 | static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { | 2664 | static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { |
2665 | .make_group = &target_core_alua_create_tg_pt_gp, | 2665 | .make_group = &target_core_alua_create_tg_pt_gp, |
2666 | .drop_item = &target_core_alua_drop_tg_pt_gp, | 2666 | .drop_item = &target_core_alua_drop_tg_pt_gp, |
2667 | }; | 2667 | }; |
2668 | 2668 | ||
2669 | static struct config_item_type target_core_alua_tg_pt_gps_cit = { | 2669 | static struct config_item_type target_core_alua_tg_pt_gps_cit = { |
2670 | .ct_group_ops = &target_core_alua_tg_pt_gps_group_ops, | 2670 | .ct_group_ops = &target_core_alua_tg_pt_gps_group_ops, |
2671 | .ct_owner = THIS_MODULE, | 2671 | .ct_owner = THIS_MODULE, |
2672 | }; | 2672 | }; |
2673 | 2673 | ||
2674 | /* End functions for struct config_item_type target_core_alua_tg_pt_gps_cit */ | 2674 | /* End functions for struct config_item_type target_core_alua_tg_pt_gps_cit */ |
2675 | 2675 | ||
2676 | /* Start functions for struct config_item_type target_core_alua_cit */ | 2676 | /* Start functions for struct config_item_type target_core_alua_cit */ |
2677 | 2677 | ||
2678 | /* | 2678 | /* |
2679 | * target_core_alua_cit is a ConfigFS group that lives under | 2679 | * target_core_alua_cit is a ConfigFS group that lives under |
2680 | * /sys/kernel/config/target/core/alua. There are default groups | 2680 | * /sys/kernel/config/target/core/alua. There are default groups |
2681 | * core/alua/lu_gps and core/alua/tg_pt_gps that are attached to | 2681 | * core/alua/lu_gps and core/alua/tg_pt_gps that are attached to |
2682 | * target_core_alua_cit in target_core_init_configfs() below. | 2682 | * target_core_alua_cit in target_core_init_configfs() below. |
2683 | */ | 2683 | */ |
2684 | static struct config_item_type target_core_alua_cit = { | 2684 | static struct config_item_type target_core_alua_cit = { |
2685 | .ct_item_ops = NULL, | 2685 | .ct_item_ops = NULL, |
2686 | .ct_attrs = NULL, | 2686 | .ct_attrs = NULL, |
2687 | .ct_owner = THIS_MODULE, | 2687 | .ct_owner = THIS_MODULE, |
2688 | }; | 2688 | }; |
2689 | 2689 | ||
2690 | /* End functions for struct config_item_type target_core_alua_cit */ | 2690 | /* End functions for struct config_item_type target_core_alua_cit */ |
2691 | 2691 | ||
2692 | /* Start functions for struct config_item_type target_core_stat_cit */ | 2692 | /* Start functions for struct config_item_type target_core_stat_cit */ |
2693 | 2693 | ||
2694 | static struct config_group *target_core_stat_mkdir( | 2694 | static struct config_group *target_core_stat_mkdir( |
2695 | struct config_group *group, | 2695 | struct config_group *group, |
2696 | const char *name) | 2696 | const char *name) |
2697 | { | 2697 | { |
2698 | return ERR_PTR(-ENOSYS); | 2698 | return ERR_PTR(-ENOSYS); |
2699 | } | 2699 | } |
2700 | 2700 | ||
2701 | static void target_core_stat_rmdir( | 2701 | static void target_core_stat_rmdir( |
2702 | struct config_group *group, | 2702 | struct config_group *group, |
2703 | struct config_item *item) | 2703 | struct config_item *item) |
2704 | { | 2704 | { |
2705 | return; | 2705 | return; |
2706 | } | 2706 | } |
2707 | 2707 | ||
2708 | static struct configfs_group_operations target_core_stat_group_ops = { | 2708 | static struct configfs_group_operations target_core_stat_group_ops = { |
2709 | .make_group = &target_core_stat_mkdir, | 2709 | .make_group = &target_core_stat_mkdir, |
2710 | .drop_item = &target_core_stat_rmdir, | 2710 | .drop_item = &target_core_stat_rmdir, |
2711 | }; | 2711 | }; |
2712 | 2712 | ||
2713 | static struct config_item_type target_core_stat_cit = { | 2713 | static struct config_item_type target_core_stat_cit = { |
2714 | .ct_group_ops = &target_core_stat_group_ops, | 2714 | .ct_group_ops = &target_core_stat_group_ops, |
2715 | .ct_owner = THIS_MODULE, | 2715 | .ct_owner = THIS_MODULE, |
2716 | }; | 2716 | }; |
2717 | 2717 | ||
2718 | /* End functions for struct config_item_type target_core_stat_cit */ | 2718 | /* End functions for struct config_item_type target_core_stat_cit */ |
2719 | 2719 | ||
2720 | /* Start functions for struct config_item_type target_core_hba_cit */ | 2720 | /* Start functions for struct config_item_type target_core_hba_cit */ |
2721 | 2721 | ||
2722 | static struct config_group *target_core_make_subdev( | 2722 | static struct config_group *target_core_make_subdev( |
2723 | struct config_group *group, | 2723 | struct config_group *group, |
2724 | const char *name) | 2724 | const char *name) |
2725 | { | 2725 | { |
2726 | struct t10_alua_tg_pt_gp *tg_pt_gp; | 2726 | struct t10_alua_tg_pt_gp *tg_pt_gp; |
2727 | struct se_subsystem_dev *se_dev; | 2727 | struct se_subsystem_dev *se_dev; |
2728 | struct se_subsystem_api *t; | 2728 | struct se_subsystem_api *t; |
2729 | struct config_item *hba_ci = &group->cg_item; | 2729 | struct config_item *hba_ci = &group->cg_item; |
2730 | struct se_hba *hba = item_to_hba(hba_ci); | 2730 | struct se_hba *hba = item_to_hba(hba_ci); |
2731 | struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; | 2731 | struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; |
2732 | struct config_group *dev_stat_grp = NULL; | 2732 | struct config_group *dev_stat_grp = NULL; |
2733 | int errno = -ENOMEM, ret; | 2733 | int errno = -ENOMEM, ret; |
2734 | 2734 | ||
2735 | ret = mutex_lock_interruptible(&hba->hba_access_mutex); | 2735 | ret = mutex_lock_interruptible(&hba->hba_access_mutex); |
2736 | if (ret) | 2736 | if (ret) |
2737 | return ERR_PTR(ret); | 2737 | return ERR_PTR(ret); |
2738 | /* | 2738 | /* |
2739 | * Locate the struct se_subsystem_api from parent's struct se_hba. | 2739 | * Locate the struct se_subsystem_api from parent's struct se_hba. |
2740 | */ | 2740 | */ |
2741 | t = hba->transport; | 2741 | t = hba->transport; |
2742 | 2742 | ||
2743 | se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); | 2743 | se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); |
2744 | if (!se_dev) { | 2744 | if (!se_dev) { |
2745 | pr_err("Unable to allocate memory for" | 2745 | pr_err("Unable to allocate memory for" |
2746 | " struct se_subsystem_dev\n"); | 2746 | " struct se_subsystem_dev\n"); |
2747 | goto unlock; | 2747 | goto unlock; |
2748 | } | 2748 | } |
2749 | INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); | 2749 | INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); |
2750 | spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); | 2750 | spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); |
2751 | INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); | 2751 | INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); |
2752 | INIT_LIST_HEAD(&se_dev->t10_pr.aptpl_reg_list); | 2752 | INIT_LIST_HEAD(&se_dev->t10_pr.aptpl_reg_list); |
2753 | spin_lock_init(&se_dev->t10_pr.registration_lock); | 2753 | spin_lock_init(&se_dev->t10_pr.registration_lock); |
2754 | spin_lock_init(&se_dev->t10_pr.aptpl_reg_lock); | 2754 | spin_lock_init(&se_dev->t10_pr.aptpl_reg_lock); |
2755 | INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); | 2755 | INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); |
2756 | spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); | 2756 | spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); |
2757 | spin_lock_init(&se_dev->se_dev_lock); | 2757 | spin_lock_init(&se_dev->se_dev_lock); |
2758 | se_dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; | 2758 | se_dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; |
2759 | se_dev->t10_wwn.t10_sub_dev = se_dev; | 2759 | se_dev->t10_wwn.t10_sub_dev = se_dev; |
2760 | se_dev->t10_alua.t10_sub_dev = se_dev; | 2760 | se_dev->t10_alua.t10_sub_dev = se_dev; |
2761 | se_dev->se_dev_attrib.da_sub_dev = se_dev; | 2761 | se_dev->se_dev_attrib.da_sub_dev = se_dev; |
2762 | 2762 | ||
2763 | se_dev->se_dev_hba = hba; | 2763 | se_dev->se_dev_hba = hba; |
2764 | dev_cg = &se_dev->se_dev_group; | 2764 | dev_cg = &se_dev->se_dev_group; |
2765 | 2765 | ||
2766 | dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, | 2766 | dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, |
2767 | GFP_KERNEL); | 2767 | GFP_KERNEL); |
2768 | if (!dev_cg->default_groups) | 2768 | if (!dev_cg->default_groups) |
2769 | goto out; | 2769 | goto out; |
2770 | /* | 2770 | /* |
2771 | * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr | 2771 | * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr |
2772 | * for ->allocate_virtdevice() | 2772 | * for ->allocate_virtdevice() |
2773 | * | 2773 | * |
2774 | * se_dev->se_dev_ptr will be set after ->create_virtdev() | 2774 | * se_dev->se_dev_ptr will be set after ->create_virtdev() |
2775 | * has been called successfully in the next level up in the | 2775 | * has been called successfully in the next level up in the |
2776 | * configfs tree for device object's struct config_group. | 2776 | * configfs tree for device object's struct config_group. |
2777 | */ | 2777 | */ |
2778 | se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name); | 2778 | se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name); |
2779 | if (!se_dev->se_dev_su_ptr) { | 2779 | if (!se_dev->se_dev_su_ptr) { |
2780 | pr_err("Unable to locate subsystem dependent pointer" | 2780 | pr_err("Unable to locate subsystem dependent pointer" |
2781 | " from allocate_virtdevice()\n"); | 2781 | " from allocate_virtdevice()\n"); |
2782 | goto out; | 2782 | goto out; |
2783 | } | 2783 | } |
2784 | 2784 | ||
2785 | config_group_init_type_name(&se_dev->se_dev_group, name, | 2785 | config_group_init_type_name(&se_dev->se_dev_group, name, |
2786 | &target_core_dev_cit); | 2786 | &target_core_dev_cit); |
2787 | config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib", | 2787 | config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib", |
2788 | &target_core_dev_attrib_cit); | 2788 | &target_core_dev_attrib_cit); |
2789 | config_group_init_type_name(&se_dev->se_dev_pr_group, "pr", | 2789 | config_group_init_type_name(&se_dev->se_dev_pr_group, "pr", |
2790 | &target_core_dev_pr_cit); | 2790 | &target_core_dev_pr_cit); |
2791 | config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn", | 2791 | config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn", |
2792 | &target_core_dev_wwn_cit); | 2792 | &target_core_dev_wwn_cit); |
2793 | config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, | 2793 | config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, |
2794 | "alua", &target_core_alua_tg_pt_gps_cit); | 2794 | "alua", &target_core_alua_tg_pt_gps_cit); |
2795 | config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, | 2795 | config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, |
2796 | "statistics", &target_core_stat_cit); | 2796 | "statistics", &target_core_stat_cit); |
2797 | 2797 | ||
2798 | dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; | 2798 | dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; |
2799 | dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; | 2799 | dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; |
2800 | dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; | 2800 | dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; |
2801 | dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; | 2801 | dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; |
2802 | dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; | 2802 | dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; |
2803 | dev_cg->default_groups[5] = NULL; | 2803 | dev_cg->default_groups[5] = NULL; |
2804 | /* | 2804 | /* |
2805 | * Add core/$HBA/$DEV/alua/default_tg_pt_gp | 2805 | * Add core/$HBA/$DEV/alua/default_tg_pt_gp |
2806 | */ | 2806 | */ |
2807 | tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); | 2807 | tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); |
2808 | if (!tg_pt_gp) | 2808 | if (!tg_pt_gp) |
2809 | goto out; | 2809 | goto out; |
2810 | 2810 | ||
2811 | tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; | 2811 | tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; |
2812 | tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | 2812 | tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, |
2813 | GFP_KERNEL); | 2813 | GFP_KERNEL); |
2814 | if (!tg_pt_gp_cg->default_groups) { | 2814 | if (!tg_pt_gp_cg->default_groups) { |
2815 | pr_err("Unable to allocate tg_pt_gp_cg->" | 2815 | pr_err("Unable to allocate tg_pt_gp_cg->" |
2816 | "default_groups\n"); | 2816 | "default_groups\n"); |
2817 | goto out; | 2817 | goto out; |
2818 | } | 2818 | } |
2819 | 2819 | ||
2820 | config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group, | 2820 | config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group, |
2821 | "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit); | 2821 | "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit); |
2822 | tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; | 2822 | tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; |
2823 | tg_pt_gp_cg->default_groups[1] = NULL; | 2823 | tg_pt_gp_cg->default_groups[1] = NULL; |
2824 | se_dev->t10_alua.default_tg_pt_gp = tg_pt_gp; | 2824 | se_dev->t10_alua.default_tg_pt_gp = tg_pt_gp; |
2825 | /* | 2825 | /* |
2826 | * Add core/$HBA/$DEV/statistics/ default groups | 2826 | * Add core/$HBA/$DEV/statistics/ default groups |
2827 | */ | 2827 | */ |
2828 | dev_stat_grp = &se_dev->dev_stat_grps.stat_group; | 2828 | dev_stat_grp = &se_dev->dev_stat_grps.stat_group; |
2829 | dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, | 2829 | dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, |
2830 | GFP_KERNEL); | 2830 | GFP_KERNEL); |
2831 | if (!dev_stat_grp->default_groups) { | 2831 | if (!dev_stat_grp->default_groups) { |
2832 | pr_err("Unable to allocate dev_stat_grp->default_groups\n"); | 2832 | pr_err("Unable to allocate dev_stat_grp->default_groups\n"); |
2833 | goto out; | 2833 | goto out; |
2834 | } | 2834 | } |
2835 | target_stat_setup_dev_default_groups(se_dev); | 2835 | target_stat_setup_dev_default_groups(se_dev); |
2836 | 2836 | ||
2837 | pr_debug("Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" | 2837 | pr_debug("Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" |
2838 | " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); | 2838 | " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); |
2839 | 2839 | ||
2840 | mutex_unlock(&hba->hba_access_mutex); | 2840 | mutex_unlock(&hba->hba_access_mutex); |
2841 | return &se_dev->se_dev_group; | 2841 | return &se_dev->se_dev_group; |
2842 | out: | 2842 | out: |
2843 | if (se_dev->t10_alua.default_tg_pt_gp) { | 2843 | if (se_dev->t10_alua.default_tg_pt_gp) { |
2844 | core_alua_free_tg_pt_gp(se_dev->t10_alua.default_tg_pt_gp); | 2844 | core_alua_free_tg_pt_gp(se_dev->t10_alua.default_tg_pt_gp); |
2845 | se_dev->t10_alua.default_tg_pt_gp = NULL; | 2845 | se_dev->t10_alua.default_tg_pt_gp = NULL; |
2846 | } | 2846 | } |
2847 | if (dev_stat_grp) | 2847 | if (dev_stat_grp) |
2848 | kfree(dev_stat_grp->default_groups); | 2848 | kfree(dev_stat_grp->default_groups); |
2849 | if (tg_pt_gp_cg) | 2849 | if (tg_pt_gp_cg) |
2850 | kfree(tg_pt_gp_cg->default_groups); | 2850 | kfree(tg_pt_gp_cg->default_groups); |
2851 | if (dev_cg) | 2851 | if (dev_cg) |
2852 | kfree(dev_cg->default_groups); | 2852 | kfree(dev_cg->default_groups); |
2853 | if (se_dev->se_dev_su_ptr) | 2853 | if (se_dev->se_dev_su_ptr) |
2854 | t->free_device(se_dev->se_dev_su_ptr); | 2854 | t->free_device(se_dev->se_dev_su_ptr); |
2855 | kfree(se_dev); | 2855 | kfree(se_dev); |
2856 | unlock: | 2856 | unlock: |
2857 | mutex_unlock(&hba->hba_access_mutex); | 2857 | mutex_unlock(&hba->hba_access_mutex); |
2858 | return ERR_PTR(errno); | 2858 | return ERR_PTR(errno); |
2859 | } | 2859 | } |
2860 | 2860 | ||
2861 | static void target_core_drop_subdev( | 2861 | static void target_core_drop_subdev( |
2862 | struct config_group *group, | 2862 | struct config_group *group, |
2863 | struct config_item *item) | 2863 | struct config_item *item) |
2864 | { | 2864 | { |
2865 | struct se_subsystem_dev *se_dev = container_of(to_config_group(item), | 2865 | struct se_subsystem_dev *se_dev = container_of(to_config_group(item), |
2866 | struct se_subsystem_dev, se_dev_group); | 2866 | struct se_subsystem_dev, se_dev_group); |
2867 | struct se_hba *hba; | 2867 | struct se_hba *hba; |
2868 | struct se_subsystem_api *t; | 2868 | struct se_subsystem_api *t; |
2869 | struct config_item *df_item; | 2869 | struct config_item *df_item; |
2870 | struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; | 2870 | struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; |
2871 | int i; | 2871 | int i; |
2872 | 2872 | ||
2873 | hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); | 2873 | hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); |
2874 | 2874 | ||
2875 | mutex_lock(&hba->hba_access_mutex); | 2875 | mutex_lock(&hba->hba_access_mutex); |
2876 | t = hba->transport; | 2876 | t = hba->transport; |
2877 | 2877 | ||
2878 | dev_stat_grp = &se_dev->dev_stat_grps.stat_group; | 2878 | dev_stat_grp = &se_dev->dev_stat_grps.stat_group; |
2879 | for (i = 0; dev_stat_grp->default_groups[i]; i++) { | 2879 | for (i = 0; dev_stat_grp->default_groups[i]; i++) { |
2880 | df_item = &dev_stat_grp->default_groups[i]->cg_item; | 2880 | df_item = &dev_stat_grp->default_groups[i]->cg_item; |
2881 | dev_stat_grp->default_groups[i] = NULL; | 2881 | dev_stat_grp->default_groups[i] = NULL; |
2882 | config_item_put(df_item); | 2882 | config_item_put(df_item); |
2883 | } | 2883 | } |
2884 | kfree(dev_stat_grp->default_groups); | 2884 | kfree(dev_stat_grp->default_groups); |
2885 | 2885 | ||
2886 | tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; | 2886 | tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; |
2887 | for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { | 2887 | for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { |
2888 | df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; | 2888 | df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; |
2889 | tg_pt_gp_cg->default_groups[i] = NULL; | 2889 | tg_pt_gp_cg->default_groups[i] = NULL; |
2890 | config_item_put(df_item); | 2890 | config_item_put(df_item); |
2891 | } | 2891 | } |
2892 | kfree(tg_pt_gp_cg->default_groups); | 2892 | kfree(tg_pt_gp_cg->default_groups); |
2893 | /* | 2893 | /* |
2894 | * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp | 2894 | * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp |
2895 | * directly from target_core_alua_tg_pt_gp_release(). | 2895 | * directly from target_core_alua_tg_pt_gp_release(). |
2896 | */ | 2896 | */ |
2897 | se_dev->t10_alua.default_tg_pt_gp = NULL; | 2897 | se_dev->t10_alua.default_tg_pt_gp = NULL; |
2898 | 2898 | ||
2899 | dev_cg = &se_dev->se_dev_group; | 2899 | dev_cg = &se_dev->se_dev_group; |
2900 | for (i = 0; dev_cg->default_groups[i]; i++) { | 2900 | for (i = 0; dev_cg->default_groups[i]; i++) { |
2901 | df_item = &dev_cg->default_groups[i]->cg_item; | 2901 | df_item = &dev_cg->default_groups[i]->cg_item; |
2902 | dev_cg->default_groups[i] = NULL; | 2902 | dev_cg->default_groups[i] = NULL; |
2903 | config_item_put(df_item); | 2903 | config_item_put(df_item); |
2904 | } | 2904 | } |
2905 | /* | 2905 | /* |
2906 | * The releasing of se_dev and associated se_dev->se_dev_ptr is done | 2906 | * The releasing of se_dev and associated se_dev->se_dev_ptr is done |
2907 | * from target_core_dev_item_ops->release() ->target_core_dev_release(). | 2907 | * from target_core_dev_item_ops->release() ->target_core_dev_release(). |
2908 | */ | 2908 | */ |
2909 | config_item_put(item); | 2909 | config_item_put(item); |
2910 | mutex_unlock(&hba->hba_access_mutex); | 2910 | mutex_unlock(&hba->hba_access_mutex); |
2911 | } | 2911 | } |
2912 | 2912 | ||
2913 | static struct configfs_group_operations target_core_hba_group_ops = { | 2913 | static struct configfs_group_operations target_core_hba_group_ops = { |
2914 | .make_group = target_core_make_subdev, | 2914 | .make_group = target_core_make_subdev, |
2915 | .drop_item = target_core_drop_subdev, | 2915 | .drop_item = target_core_drop_subdev, |
2916 | }; | 2916 | }; |
2917 | 2917 | ||
2918 | CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba); | 2918 | CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba); |
2919 | #define SE_HBA_ATTR(_name, _mode) \ | 2919 | #define SE_HBA_ATTR(_name, _mode) \ |
2920 | static struct target_core_hba_attribute \ | 2920 | static struct target_core_hba_attribute \ |
2921 | target_core_hba_##_name = \ | 2921 | target_core_hba_##_name = \ |
2922 | __CONFIGFS_EATTR(_name, _mode, \ | 2922 | __CONFIGFS_EATTR(_name, _mode, \ |
2923 | target_core_hba_show_attr_##_name, \ | 2923 | target_core_hba_show_attr_##_name, \ |
2924 | target_core_hba_store_attr_##_name); | 2924 | target_core_hba_store_attr_##_name); |
2925 | 2925 | ||
2926 | #define SE_HBA_ATTR_RO(_name) \ | 2926 | #define SE_HBA_ATTR_RO(_name) \ |
2927 | static struct target_core_hba_attribute \ | 2927 | static struct target_core_hba_attribute \ |
2928 | target_core_hba_##_name = \ | 2928 | target_core_hba_##_name = \ |
2929 | __CONFIGFS_EATTR_RO(_name, \ | 2929 | __CONFIGFS_EATTR_RO(_name, \ |
2930 | target_core_hba_show_attr_##_name); | 2930 | target_core_hba_show_attr_##_name); |
2931 | 2931 | ||
2932 | static ssize_t target_core_hba_show_attr_hba_info( | 2932 | static ssize_t target_core_hba_show_attr_hba_info( |
2933 | struct se_hba *hba, | 2933 | struct se_hba *hba, |
2934 | char *page) | 2934 | char *page) |
2935 | { | 2935 | { |
2936 | return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", | 2936 | return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", |
2937 | hba->hba_id, hba->transport->name, | 2937 | hba->hba_id, hba->transport->name, |
2938 | TARGET_CORE_CONFIGFS_VERSION); | 2938 | TARGET_CORE_CONFIGFS_VERSION); |
2939 | } | 2939 | } |
2940 | 2940 | ||
2941 | SE_HBA_ATTR_RO(hba_info); | 2941 | SE_HBA_ATTR_RO(hba_info); |
2942 | 2942 | ||
2943 | static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, | 2943 | static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, |
2944 | char *page) | 2944 | char *page) |
2945 | { | 2945 | { |
2946 | int hba_mode = 0; | 2946 | int hba_mode = 0; |
2947 | 2947 | ||
2948 | if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE) | 2948 | if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE) |
2949 | hba_mode = 1; | 2949 | hba_mode = 1; |
2950 | 2950 | ||
2951 | return sprintf(page, "%d\n", hba_mode); | 2951 | return sprintf(page, "%d\n", hba_mode); |
2952 | } | 2952 | } |
2953 | 2953 | ||
2954 | static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, | 2954 | static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, |
2955 | const char *page, size_t count) | 2955 | const char *page, size_t count) |
2956 | { | 2956 | { |
2957 | struct se_subsystem_api *transport = hba->transport; | 2957 | struct se_subsystem_api *transport = hba->transport; |
2958 | unsigned long mode_flag; | 2958 | unsigned long mode_flag; |
2959 | int ret; | 2959 | int ret; |
2960 | 2960 | ||
2961 | if (transport->pmode_enable_hba == NULL) | 2961 | if (transport->pmode_enable_hba == NULL) |
2962 | return -EINVAL; | 2962 | return -EINVAL; |
2963 | 2963 | ||
2964 | ret = strict_strtoul(page, 0, &mode_flag); | 2964 | ret = strict_strtoul(page, 0, &mode_flag); |
2965 | if (ret < 0) { | 2965 | if (ret < 0) { |
2966 | pr_err("Unable to extract hba mode flag: %d\n", ret); | 2966 | pr_err("Unable to extract hba mode flag: %d\n", ret); |
2967 | return -EINVAL; | 2967 | return -EINVAL; |
2968 | } | 2968 | } |
2969 | 2969 | ||
2970 | spin_lock(&hba->device_lock); | 2970 | spin_lock(&hba->device_lock); |
2971 | if (!list_empty(&hba->hba_dev_list)) { | 2971 | if (!list_empty(&hba->hba_dev_list)) { |
2972 | pr_err("Unable to set hba_mode with active devices\n"); | 2972 | pr_err("Unable to set hba_mode with active devices\n"); |
2973 | spin_unlock(&hba->device_lock); | 2973 | spin_unlock(&hba->device_lock); |
2974 | return -EINVAL; | 2974 | return -EINVAL; |
2975 | } | 2975 | } |
2976 | spin_unlock(&hba->device_lock); | 2976 | spin_unlock(&hba->device_lock); |
2977 | 2977 | ||
2978 | ret = transport->pmode_enable_hba(hba, mode_flag); | 2978 | ret = transport->pmode_enable_hba(hba, mode_flag); |
2979 | if (ret < 0) | 2979 | if (ret < 0) |
2980 | return -EINVAL; | 2980 | return -EINVAL; |
2981 | if (ret > 0) | 2981 | if (ret > 0) |
2982 | hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; | 2982 | hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; |
2983 | else if (ret == 0) | 2983 | else if (ret == 0) |
2984 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; | 2984 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; |
2985 | 2985 | ||
2986 | return count; | 2986 | return count; |
2987 | } | 2987 | } |
2988 | 2988 | ||
2989 | SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR); | 2989 | SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR); |
2990 | 2990 | ||
2991 | CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group); | 2991 | CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group); |
2992 | 2992 | ||
2993 | static void target_core_hba_release(struct config_item *item) | 2993 | static void target_core_hba_release(struct config_item *item) |
2994 | { | 2994 | { |
2995 | struct se_hba *hba = container_of(to_config_group(item), | 2995 | struct se_hba *hba = container_of(to_config_group(item), |
2996 | struct se_hba, hba_group); | 2996 | struct se_hba, hba_group); |
2997 | core_delete_hba(hba); | 2997 | core_delete_hba(hba); |
2998 | } | 2998 | } |
2999 | 2999 | ||
3000 | static struct configfs_attribute *target_core_hba_attrs[] = { | 3000 | static struct configfs_attribute *target_core_hba_attrs[] = { |
3001 | &target_core_hba_hba_info.attr, | 3001 | &target_core_hba_hba_info.attr, |
3002 | &target_core_hba_hba_mode.attr, | 3002 | &target_core_hba_hba_mode.attr, |
3003 | NULL, | 3003 | NULL, |
3004 | }; | 3004 | }; |
3005 | 3005 | ||
3006 | static struct configfs_item_operations target_core_hba_item_ops = { | 3006 | static struct configfs_item_operations target_core_hba_item_ops = { |
3007 | .release = target_core_hba_release, | 3007 | .release = target_core_hba_release, |
3008 | .show_attribute = target_core_hba_attr_show, | 3008 | .show_attribute = target_core_hba_attr_show, |
3009 | .store_attribute = target_core_hba_attr_store, | 3009 | .store_attribute = target_core_hba_attr_store, |
3010 | }; | 3010 | }; |
3011 | 3011 | ||
3012 | static struct config_item_type target_core_hba_cit = { | 3012 | static struct config_item_type target_core_hba_cit = { |
3013 | .ct_item_ops = &target_core_hba_item_ops, | 3013 | .ct_item_ops = &target_core_hba_item_ops, |
3014 | .ct_group_ops = &target_core_hba_group_ops, | 3014 | .ct_group_ops = &target_core_hba_group_ops, |
3015 | .ct_attrs = target_core_hba_attrs, | 3015 | .ct_attrs = target_core_hba_attrs, |
3016 | .ct_owner = THIS_MODULE, | 3016 | .ct_owner = THIS_MODULE, |
3017 | }; | 3017 | }; |
3018 | 3018 | ||
3019 | static struct config_group *target_core_call_addhbatotarget( | 3019 | static struct config_group *target_core_call_addhbatotarget( |
3020 | struct config_group *group, | 3020 | struct config_group *group, |
3021 | const char *name) | 3021 | const char *name) |
3022 | { | 3022 | { |
3023 | char *se_plugin_str, *str, *str2; | 3023 | char *se_plugin_str, *str, *str2; |
3024 | struct se_hba *hba; | 3024 | struct se_hba *hba; |
3025 | char buf[TARGET_CORE_NAME_MAX_LEN]; | 3025 | char buf[TARGET_CORE_NAME_MAX_LEN]; |
3026 | unsigned long plugin_dep_id = 0; | 3026 | unsigned long plugin_dep_id = 0; |
3027 | int ret; | 3027 | int ret; |
3028 | 3028 | ||
3029 | memset(buf, 0, TARGET_CORE_NAME_MAX_LEN); | 3029 | memset(buf, 0, TARGET_CORE_NAME_MAX_LEN); |
3030 | if (strlen(name) >= TARGET_CORE_NAME_MAX_LEN) { | 3030 | if (strlen(name) >= TARGET_CORE_NAME_MAX_LEN) { |
3031 | pr_err("Passed *name strlen(): %d exceeds" | 3031 | pr_err("Passed *name strlen(): %d exceeds" |
3032 | " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name), | 3032 | " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name), |
3033 | TARGET_CORE_NAME_MAX_LEN); | 3033 | TARGET_CORE_NAME_MAX_LEN); |
3034 | return ERR_PTR(-ENAMETOOLONG); | 3034 | return ERR_PTR(-ENAMETOOLONG); |
3035 | } | 3035 | } |
3036 | snprintf(buf, TARGET_CORE_NAME_MAX_LEN, "%s", name); | 3036 | snprintf(buf, TARGET_CORE_NAME_MAX_LEN, "%s", name); |
3037 | 3037 | ||
3038 | str = strstr(buf, "_"); | 3038 | str = strstr(buf, "_"); |
3039 | if (!str) { | 3039 | if (!str) { |
3040 | pr_err("Unable to locate \"_\" for $SUBSYSTEM_PLUGIN_$HOST_ID\n"); | 3040 | pr_err("Unable to locate \"_\" for $SUBSYSTEM_PLUGIN_$HOST_ID\n"); |
3041 | return ERR_PTR(-EINVAL); | 3041 | return ERR_PTR(-EINVAL); |
3042 | } | 3042 | } |
3043 | se_plugin_str = buf; | 3043 | se_plugin_str = buf; |
3044 | /* | 3044 | /* |
3045 | * Special case for subsystem plugins that have "_" in their names. | 3045 | * Special case for subsystem plugins that have "_" in their names. |
3046 | * Namely rd_direct and rd_mcp.. | 3046 | * Namely rd_direct and rd_mcp.. |
3047 | */ | 3047 | */ |
3048 | str2 = strstr(str+1, "_"); | 3048 | str2 = strstr(str+1, "_"); |
3049 | if (str2) { | 3049 | if (str2) { |
3050 | *str2 = '\0'; /* Terminate for *se_plugin_str */ | 3050 | *str2 = '\0'; /* Terminate for *se_plugin_str */ |
3051 | str2++; /* Skip to start of plugin dependent ID */ | 3051 | str2++; /* Skip to start of plugin dependent ID */ |
3052 | str = str2; | 3052 | str = str2; |
3053 | } else { | 3053 | } else { |
3054 | *str = '\0'; /* Terminate for *se_plugin_str */ | 3054 | *str = '\0'; /* Terminate for *se_plugin_str */ |
3055 | str++; /* Skip to start of plugin dependent ID */ | 3055 | str++; /* Skip to start of plugin dependent ID */ |
3056 | } | 3056 | } |
3057 | 3057 | ||
3058 | ret = strict_strtoul(str, 0, &plugin_dep_id); | 3058 | ret = strict_strtoul(str, 0, &plugin_dep_id); |
3059 | if (ret < 0) { | 3059 | if (ret < 0) { |
3060 | pr_err("strict_strtoul() returned %d for" | 3060 | pr_err("strict_strtoul() returned %d for" |
3061 | " plugin_dep_id\n", ret); | 3061 | " plugin_dep_id\n", ret); |
3062 | return ERR_PTR(-EINVAL); | 3062 | return ERR_PTR(-EINVAL); |
3063 | } | 3063 | } |
3064 | /* | 3064 | /* |
3065 | * Load up TCM subsystem plugins if they have not already been loaded. | 3065 | * Load up TCM subsystem plugins if they have not already been loaded. |
3066 | */ | 3066 | */ |
3067 | transport_subsystem_check_init(); | 3067 | transport_subsystem_check_init(); |
3068 | 3068 | ||
3069 | hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0); | 3069 | hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0); |
3070 | if (IS_ERR(hba)) | 3070 | if (IS_ERR(hba)) |
3071 | return ERR_CAST(hba); | 3071 | return ERR_CAST(hba); |
3072 | 3072 | ||
3073 | config_group_init_type_name(&hba->hba_group, name, | 3073 | config_group_init_type_name(&hba->hba_group, name, |
3074 | &target_core_hba_cit); | 3074 | &target_core_hba_cit); |
3075 | 3075 | ||
3076 | return &hba->hba_group; | 3076 | return &hba->hba_group; |
3077 | } | 3077 | } |
3078 | 3078 | ||
3079 | static void target_core_call_delhbafromtarget( | 3079 | static void target_core_call_delhbafromtarget( |
3080 | struct config_group *group, | 3080 | struct config_group *group, |
3081 | struct config_item *item) | 3081 | struct config_item *item) |
3082 | { | 3082 | { |
3083 | /* | 3083 | /* |
3084 | * core_delete_hba() is called from target_core_hba_item_ops->release() | 3084 | * core_delete_hba() is called from target_core_hba_item_ops->release() |
3085 | * -> target_core_hba_release() | 3085 | * -> target_core_hba_release() |
3086 | */ | 3086 | */ |
3087 | config_item_put(item); | 3087 | config_item_put(item); |
3088 | } | 3088 | } |
3089 | 3089 | ||
3090 | static struct configfs_group_operations target_core_group_ops = { | 3090 | static struct configfs_group_operations target_core_group_ops = { |
3091 | .make_group = target_core_call_addhbatotarget, | 3091 | .make_group = target_core_call_addhbatotarget, |
3092 | .drop_item = target_core_call_delhbafromtarget, | 3092 | .drop_item = target_core_call_delhbafromtarget, |
3093 | }; | 3093 | }; |
3094 | 3094 | ||
3095 | static struct config_item_type target_core_cit = { | 3095 | static struct config_item_type target_core_cit = { |
3096 | .ct_item_ops = NULL, | 3096 | .ct_item_ops = NULL, |
3097 | .ct_group_ops = &target_core_group_ops, | 3097 | .ct_group_ops = &target_core_group_ops, |
3098 | .ct_attrs = NULL, | 3098 | .ct_attrs = NULL, |
3099 | .ct_owner = THIS_MODULE, | 3099 | .ct_owner = THIS_MODULE, |
3100 | }; | 3100 | }; |
3101 | 3101 | ||
3102 | /* Stop functions for struct config_item_type target_core_hba_cit */ | 3102 | /* Stop functions for struct config_item_type target_core_hba_cit */ |
3103 | 3103 | ||
3104 | static int __init target_core_init_configfs(void) | 3104 | static int __init target_core_init_configfs(void) |
3105 | { | 3105 | { |
3106 | struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; | 3106 | struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; |
3107 | struct config_group *lu_gp_cg = NULL; | 3107 | struct config_group *lu_gp_cg = NULL; |
3108 | struct configfs_subsystem *subsys; | 3108 | struct configfs_subsystem *subsys; |
3109 | struct t10_alua_lu_gp *lu_gp; | 3109 | struct t10_alua_lu_gp *lu_gp; |
3110 | int ret; | 3110 | int ret; |
3111 | 3111 | ||
3112 | pr_debug("TARGET_CORE[0]: Loading Generic Kernel Storage" | 3112 | pr_debug("TARGET_CORE[0]: Loading Generic Kernel Storage" |
3113 | " Engine: %s on %s/%s on "UTS_RELEASE"\n", | 3113 | " Engine: %s on %s/%s on "UTS_RELEASE"\n", |
3114 | TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); | 3114 | TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); |
3115 | 3115 | ||
3116 | subsys = target_core_subsystem[0]; | 3116 | subsys = target_core_subsystem[0]; |
3117 | config_group_init(&subsys->su_group); | 3117 | config_group_init(&subsys->su_group); |
3118 | mutex_init(&subsys->su_mutex); | 3118 | mutex_init(&subsys->su_mutex); |
3119 | 3119 | ||
3120 | INIT_LIST_HEAD(&g_tf_list); | ||
3121 | mutex_init(&g_tf_lock); | ||
3122 | ret = init_se_kmem_caches(); | 3120 | ret = init_se_kmem_caches(); |
3123 | if (ret < 0) | 3121 | if (ret < 0) |
3124 | return ret; | 3122 | return ret; |
3125 | /* | 3123 | /* |
3126 | * Create $CONFIGFS/target/core default group for HBA <-> Storage Object | 3124 | * Create $CONFIGFS/target/core default group for HBA <-> Storage Object |
3127 | * and ALUA Logical Unit Group and Target Port Group infrastructure. | 3125 | * and ALUA Logical Unit Group and Target Port Group infrastructure. |
3128 | */ | 3126 | */ |
3129 | target_cg = &subsys->su_group; | 3127 | target_cg = &subsys->su_group; |
3130 | target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | 3128 | target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, |
3131 | GFP_KERNEL); | 3129 | GFP_KERNEL); |
3132 | if (!target_cg->default_groups) { | 3130 | if (!target_cg->default_groups) { |
3133 | pr_err("Unable to allocate target_cg->default_groups\n"); | 3131 | pr_err("Unable to allocate target_cg->default_groups\n"); |
3134 | goto out_global; | 3132 | goto out_global; |
3135 | } | 3133 | } |
3136 | 3134 | ||
3137 | config_group_init_type_name(&target_core_hbagroup, | 3135 | config_group_init_type_name(&target_core_hbagroup, |
3138 | "core", &target_core_cit); | 3136 | "core", &target_core_cit); |
3139 | target_cg->default_groups[0] = &target_core_hbagroup; | 3137 | target_cg->default_groups[0] = &target_core_hbagroup; |
3140 | target_cg->default_groups[1] = NULL; | 3138 | target_cg->default_groups[1] = NULL; |
3141 | /* | 3139 | /* |
3142 | * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/ | 3140 | * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/ |
3143 | */ | 3141 | */ |
3144 | hba_cg = &target_core_hbagroup; | 3142 | hba_cg = &target_core_hbagroup; |
3145 | hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | 3143 | hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, |
3146 | GFP_KERNEL); | 3144 | GFP_KERNEL); |
3147 | if (!hba_cg->default_groups) { | 3145 | if (!hba_cg->default_groups) { |
3148 | pr_err("Unable to allocate hba_cg->default_groups\n"); | 3146 | pr_err("Unable to allocate hba_cg->default_groups\n"); |
3149 | goto out_global; | 3147 | goto out_global; |
3150 | } | 3148 | } |
3151 | config_group_init_type_name(&alua_group, | 3149 | config_group_init_type_name(&alua_group, |
3152 | "alua", &target_core_alua_cit); | 3150 | "alua", &target_core_alua_cit); |
3153 | hba_cg->default_groups[0] = &alua_group; | 3151 | hba_cg->default_groups[0] = &alua_group; |
3154 | hba_cg->default_groups[1] = NULL; | 3152 | hba_cg->default_groups[1] = NULL; |
3155 | /* | 3153 | /* |
3156 | * Add ALUA Logical Unit Group and Target Port Group ConfigFS | 3154 | * Add ALUA Logical Unit Group and Target Port Group ConfigFS |
3157 | * groups under /sys/kernel/config/target/core/alua/ | 3155 | * groups under /sys/kernel/config/target/core/alua/ |
3158 | */ | 3156 | */ |
3159 | alua_cg = &alua_group; | 3157 | alua_cg = &alua_group; |
3160 | alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | 3158 | alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, |
3161 | GFP_KERNEL); | 3159 | GFP_KERNEL); |
3162 | if (!alua_cg->default_groups) { | 3160 | if (!alua_cg->default_groups) { |
3163 | pr_err("Unable to allocate alua_cg->default_groups\n"); | 3161 | pr_err("Unable to allocate alua_cg->default_groups\n"); |
3164 | goto out_global; | 3162 | goto out_global; |
3165 | } | 3163 | } |
3166 | 3164 | ||
3167 | config_group_init_type_name(&alua_lu_gps_group, | 3165 | config_group_init_type_name(&alua_lu_gps_group, |
3168 | "lu_gps", &target_core_alua_lu_gps_cit); | 3166 | "lu_gps", &target_core_alua_lu_gps_cit); |
3169 | alua_cg->default_groups[0] = &alua_lu_gps_group; | 3167 | alua_cg->default_groups[0] = &alua_lu_gps_group; |
3170 | alua_cg->default_groups[1] = NULL; | 3168 | alua_cg->default_groups[1] = NULL; |
3171 | /* | 3169 | /* |
3172 | * Add core/alua/lu_gps/default_lu_gp | 3170 | * Add core/alua/lu_gps/default_lu_gp |
3173 | */ | 3171 | */ |
3174 | lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1); | 3172 | lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1); |
3175 | if (IS_ERR(lu_gp)) | 3173 | if (IS_ERR(lu_gp)) |
3176 | goto out_global; | 3174 | goto out_global; |
3177 | 3175 | ||
3178 | lu_gp_cg = &alua_lu_gps_group; | 3176 | lu_gp_cg = &alua_lu_gps_group; |
3179 | lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | 3177 | lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, |
3180 | GFP_KERNEL); | 3178 | GFP_KERNEL); |
3181 | if (!lu_gp_cg->default_groups) { | 3179 | if (!lu_gp_cg->default_groups) { |
3182 | pr_err("Unable to allocate lu_gp_cg->default_groups\n"); | 3180 | pr_err("Unable to allocate lu_gp_cg->default_groups\n"); |
3183 | goto out_global; | 3181 | goto out_global; |
3184 | } | 3182 | } |
3185 | 3183 | ||
3186 | config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp", | 3184 | config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp", |
3187 | &target_core_alua_lu_gp_cit); | 3185 | &target_core_alua_lu_gp_cit); |
3188 | lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group; | 3186 | lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group; |
3189 | lu_gp_cg->default_groups[1] = NULL; | 3187 | lu_gp_cg->default_groups[1] = NULL; |
3190 | default_lu_gp = lu_gp; | 3188 | default_lu_gp = lu_gp; |
3191 | /* | 3189 | /* |
3192 | * Register the target_core_mod subsystem with configfs. | 3190 | * Register the target_core_mod subsystem with configfs. |
3193 | */ | 3191 | */ |
3194 | ret = configfs_register_subsystem(subsys); | 3192 | ret = configfs_register_subsystem(subsys); |
3195 | if (ret < 0) { | 3193 | if (ret < 0) { |
3196 | pr_err("Error %d while registering subsystem %s\n", | 3194 | pr_err("Error %d while registering subsystem %s\n", |
3197 | ret, subsys->su_group.cg_item.ci_namebuf); | 3195 | ret, subsys->su_group.cg_item.ci_namebuf); |
3198 | goto out_global; | 3196 | goto out_global; |
3199 | } | 3197 | } |
3200 | pr_debug("TARGET_CORE[0]: Initialized ConfigFS Fabric" | 3198 | pr_debug("TARGET_CORE[0]: Initialized ConfigFS Fabric" |
3201 | " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s" | 3199 | " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s" |
3202 | " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); | 3200 | " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); |
3203 | /* | 3201 | /* |
3204 | * Register built-in RAMDISK subsystem logic for virtual LUN 0 | 3202 | * Register built-in RAMDISK subsystem logic for virtual LUN 0 |
3205 | */ | 3203 | */ |
3206 | ret = rd_module_init(); | 3204 | ret = rd_module_init(); |
3207 | if (ret < 0) | 3205 | if (ret < 0) |
3208 | goto out; | 3206 | goto out; |
3209 | 3207 | ||
3210 | if (core_dev_setup_virtual_lun0() < 0) | 3208 | if (core_dev_setup_virtual_lun0() < 0) |
3211 | goto out; | 3209 | goto out; |
3212 | 3210 | ||
3213 | return 0; | 3211 | return 0; |
3214 | 3212 | ||
3215 | out: | 3213 | out: |
3216 | configfs_unregister_subsystem(subsys); | 3214 | configfs_unregister_subsystem(subsys); |
3217 | core_dev_release_virtual_lun0(); | 3215 | core_dev_release_virtual_lun0(); |
3218 | rd_module_exit(); | 3216 | rd_module_exit(); |
3219 | out_global: | 3217 | out_global: |
3220 | if (default_lu_gp) { | 3218 | if (default_lu_gp) { |
3221 | core_alua_free_lu_gp(default_lu_gp); | 3219 | core_alua_free_lu_gp(default_lu_gp); |
3222 | default_lu_gp = NULL; | 3220 | default_lu_gp = NULL; |
3223 | } | 3221 | } |
3224 | if (lu_gp_cg) | 3222 | if (lu_gp_cg) |
3225 | kfree(lu_gp_cg->default_groups); | 3223 | kfree(lu_gp_cg->default_groups); |
3226 | if (alua_cg) | 3224 | if (alua_cg) |
3227 | kfree(alua_cg->default_groups); | 3225 | kfree(alua_cg->default_groups); |
3228 | if (hba_cg) | 3226 | if (hba_cg) |
3229 | kfree(hba_cg->default_groups); | 3227 | kfree(hba_cg->default_groups); |
3230 | kfree(target_cg->default_groups); | 3228 | kfree(target_cg->default_groups); |
3231 | release_se_kmem_caches(); | 3229 | release_se_kmem_caches(); |
3232 | return ret; | 3230 | return ret; |
3233 | } | 3231 | } |
3234 | 3232 | ||
3235 | static void __exit target_core_exit_configfs(void) | 3233 | static void __exit target_core_exit_configfs(void) |
3236 | { | 3234 | { |
3237 | struct configfs_subsystem *subsys; | 3235 | struct configfs_subsystem *subsys; |
3238 | struct config_group *hba_cg, *alua_cg, *lu_gp_cg; | 3236 | struct config_group *hba_cg, *alua_cg, *lu_gp_cg; |
3239 | struct config_item *item; | 3237 | struct config_item *item; |
3240 | int i; | 3238 | int i; |
3241 | 3239 | ||
3242 | subsys = target_core_subsystem[0]; | 3240 | subsys = target_core_subsystem[0]; |
3243 | 3241 | ||
3244 | lu_gp_cg = &alua_lu_gps_group; | 3242 | lu_gp_cg = &alua_lu_gps_group; |
3245 | for (i = 0; lu_gp_cg->default_groups[i]; i++) { | 3243 | for (i = 0; lu_gp_cg->default_groups[i]; i++) { |
3246 | item = &lu_gp_cg->default_groups[i]->cg_item; | 3244 | item = &lu_gp_cg->default_groups[i]->cg_item; |
3247 | lu_gp_cg->default_groups[i] = NULL; | 3245 | lu_gp_cg->default_groups[i] = NULL; |
3248 | config_item_put(item); | 3246 | config_item_put(item); |
3249 | } | 3247 | } |
3250 | kfree(lu_gp_cg->default_groups); | 3248 | kfree(lu_gp_cg->default_groups); |
3251 | lu_gp_cg->default_groups = NULL; | 3249 | lu_gp_cg->default_groups = NULL; |
3252 | 3250 | ||
3253 | alua_cg = &alua_group; | 3251 | alua_cg = &alua_group; |
3254 | for (i = 0; alua_cg->default_groups[i]; i++) { | 3252 | for (i = 0; alua_cg->default_groups[i]; i++) { |
3255 | item = &alua_cg->default_groups[i]->cg_item; | 3253 | item = &alua_cg->default_groups[i]->cg_item; |
3256 | alua_cg->default_groups[i] = NULL; | 3254 | alua_cg->default_groups[i] = NULL; |
3257 | config_item_put(item); | 3255 | config_item_put(item); |
3258 | } | 3256 | } |
3259 | kfree(alua_cg->default_groups); | 3257 | kfree(alua_cg->default_groups); |
3260 | alua_cg->default_groups = NULL; | 3258 | alua_cg->default_groups = NULL; |
3261 | 3259 | ||
3262 | hba_cg = &target_core_hbagroup; | 3260 | hba_cg = &target_core_hbagroup; |
3263 | for (i = 0; hba_cg->default_groups[i]; i++) { | 3261 | for (i = 0; hba_cg->default_groups[i]; i++) { |
3264 | item = &hba_cg->default_groups[i]->cg_item; | 3262 | item = &hba_cg->default_groups[i]->cg_item; |
3265 | hba_cg->default_groups[i] = NULL; | 3263 | hba_cg->default_groups[i] = NULL; |
3266 | config_item_put(item); | 3264 | config_item_put(item); |
3267 | } | 3265 | } |
3268 | kfree(hba_cg->default_groups); | 3266 | kfree(hba_cg->default_groups); |
3269 | hba_cg->default_groups = NULL; | 3267 | hba_cg->default_groups = NULL; |
3270 | /* | 3268 | /* |
3271 | * We expect subsys->su_group.default_groups to be released | 3269 | * We expect subsys->su_group.default_groups to be released |
3272 | * by configfs subsystem provider logic.. | 3270 | * by configfs subsystem provider logic.. |
3273 | */ | 3271 | */ |
3274 | configfs_unregister_subsystem(subsys); | 3272 | configfs_unregister_subsystem(subsys); |
3275 | kfree(subsys->su_group.default_groups); | 3273 | kfree(subsys->su_group.default_groups); |
3276 | 3274 | ||
3277 | core_alua_free_lu_gp(default_lu_gp); | 3275 | core_alua_free_lu_gp(default_lu_gp); |
3278 | default_lu_gp = NULL; | 3276 | default_lu_gp = NULL; |
3279 | 3277 | ||
3280 | pr_debug("TARGET_CORE[0]: Released ConfigFS Fabric" | 3278 | pr_debug("TARGET_CORE[0]: Released ConfigFS Fabric" |
3281 | " Infrastructure\n"); | 3279 | " Infrastructure\n"); |
3282 | 3280 | ||
3283 | core_dev_release_virtual_lun0(); | 3281 | core_dev_release_virtual_lun0(); |
3284 | rd_module_exit(); | 3282 | rd_module_exit(); |
3285 | release_se_kmem_caches(); | 3283 | release_se_kmem_caches(); |
3286 | } | 3284 | } |
3287 | 3285 | ||
3288 | MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS"); | 3286 | MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS"); |
3289 | MODULE_AUTHOR("nab@Linux-iSCSI.org"); | 3287 | MODULE_AUTHOR("nab@Linux-iSCSI.org"); |
3290 | MODULE_LICENSE("GPL"); | 3288 | MODULE_LICENSE("GPL"); |
3291 | 3289 | ||
3292 | module_init(target_core_init_configfs); | 3290 | module_init(target_core_init_configfs); |
3293 | module_exit(target_core_exit_configfs); | 3291 | module_exit(target_core_exit_configfs); |
3294 | 3292 |
drivers/target/target_core_pr.c
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * Filename: target_core_pr.c | 2 | * Filename: target_core_pr.c |
3 | * | 3 | * |
4 | * This file contains SPC-3 compliant persistent reservations and | 4 | * This file contains SPC-3 compliant persistent reservations and |
5 | * legacy SPC-2 reservations with compatible reservation handling (CRH=1) | 5 | * legacy SPC-2 reservations with compatible reservation handling (CRH=1) |
6 | * | 6 | * |
7 | * Copyright (c) 2009, 2010 Rising Tide Systems | 7 | * Copyright (c) 2009, 2010 Rising Tide Systems |
8 | * Copyright (c) 2009, 2010 Linux-iSCSI.org | 8 | * Copyright (c) 2009, 2010 Linux-iSCSI.org |
9 | * | 9 | * |
10 | * Nicholas A. Bellinger <nab@kernel.org> | 10 | * Nicholas A. Bellinger <nab@kernel.org> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
14 | * the Free Software Foundation; either version 2 of the License, or | 14 | * the Free Software Foundation; either version 2 of the License, or |
15 | * (at your option) any later version. | 15 | * (at your option) any later version. |
16 | * | 16 | * |
17 | * This program is distributed in the hope that it will be useful, | 17 | * This program is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program; if not, write to the Free Software | 23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
25 | * | 25 | * |
26 | ******************************************************************************/ | 26 | ******************************************************************************/ |
27 | 27 | ||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/list.h> | 30 | #include <linux/list.h> |
31 | #include <scsi/scsi.h> | 31 | #include <scsi/scsi.h> |
32 | #include <scsi/scsi_cmnd.h> | 32 | #include <scsi/scsi_cmnd.h> |
33 | #include <asm/unaligned.h> | 33 | #include <asm/unaligned.h> |
34 | 34 | ||
35 | #include <target/target_core_base.h> | 35 | #include <target/target_core_base.h> |
36 | #include <target/target_core_backend.h> | 36 | #include <target/target_core_backend.h> |
37 | #include <target/target_core_fabric.h> | 37 | #include <target/target_core_fabric.h> |
38 | #include <target/target_core_configfs.h> | 38 | #include <target/target_core_configfs.h> |
39 | 39 | ||
40 | #include "target_core_internal.h" | 40 | #include "target_core_internal.h" |
41 | #include "target_core_pr.h" | 41 | #include "target_core_pr.h" |
42 | #include "target_core_ua.h" | 42 | #include "target_core_ua.h" |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT) | 45 | * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT) |
46 | */ | 46 | */ |
47 | struct pr_transport_id_holder { | 47 | struct pr_transport_id_holder { |
48 | int dest_local_nexus; | 48 | int dest_local_nexus; |
49 | struct t10_pr_registration *dest_pr_reg; | 49 | struct t10_pr_registration *dest_pr_reg; |
50 | struct se_portal_group *dest_tpg; | 50 | struct se_portal_group *dest_tpg; |
51 | struct se_node_acl *dest_node_acl; | 51 | struct se_node_acl *dest_node_acl; |
52 | struct se_dev_entry *dest_se_deve; | 52 | struct se_dev_entry *dest_se_deve; |
53 | struct list_head dest_list; | 53 | struct list_head dest_list; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | int core_pr_dump_initiator_port( | 56 | int core_pr_dump_initiator_port( |
57 | struct t10_pr_registration *pr_reg, | 57 | struct t10_pr_registration *pr_reg, |
58 | char *buf, | 58 | char *buf, |
59 | u32 size) | 59 | u32 size) |
60 | { | 60 | { |
61 | if (!pr_reg->isid_present_at_reg) | 61 | if (!pr_reg->isid_present_at_reg) |
62 | return 0; | 62 | return 0; |
63 | 63 | ||
64 | snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]); | 64 | snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]); |
65 | return 1; | 65 | return 1; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *, | 68 | static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *, |
69 | struct t10_pr_registration *, int); | 69 | struct t10_pr_registration *, int); |
70 | 70 | ||
71 | static int core_scsi2_reservation_seq_non_holder( | 71 | static int core_scsi2_reservation_seq_non_holder( |
72 | struct se_cmd *cmd, | 72 | struct se_cmd *cmd, |
73 | unsigned char *cdb, | 73 | unsigned char *cdb, |
74 | u32 pr_reg_type) | 74 | u32 pr_reg_type) |
75 | { | 75 | { |
76 | switch (cdb[0]) { | 76 | switch (cdb[0]) { |
77 | case INQUIRY: | 77 | case INQUIRY: |
78 | case RELEASE: | 78 | case RELEASE: |
79 | case RELEASE_10: | 79 | case RELEASE_10: |
80 | return 0; | 80 | return 0; |
81 | default: | 81 | default: |
82 | return 1; | 82 | return 1; |
83 | } | 83 | } |
84 | 84 | ||
85 | return 1; | 85 | return 1; |
86 | } | 86 | } |
87 | 87 | ||
88 | static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) | 88 | static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) |
89 | { | 89 | { |
90 | struct se_device *dev = cmd->se_dev; | 90 | struct se_device *dev = cmd->se_dev; |
91 | struct se_session *sess = cmd->se_sess; | 91 | struct se_session *sess = cmd->se_sess; |
92 | int ret; | 92 | int ret; |
93 | 93 | ||
94 | if (!sess) | 94 | if (!sess) |
95 | return 0; | 95 | return 0; |
96 | 96 | ||
97 | spin_lock(&dev->dev_reservation_lock); | 97 | spin_lock(&dev->dev_reservation_lock); |
98 | if (!dev->dev_reserved_node_acl || !sess) { | 98 | if (!dev->dev_reserved_node_acl || !sess) { |
99 | spin_unlock(&dev->dev_reservation_lock); | 99 | spin_unlock(&dev->dev_reservation_lock); |
100 | return 0; | 100 | return 0; |
101 | } | 101 | } |
102 | if (dev->dev_reserved_node_acl != sess->se_node_acl) { | 102 | if (dev->dev_reserved_node_acl != sess->se_node_acl) { |
103 | spin_unlock(&dev->dev_reservation_lock); | 103 | spin_unlock(&dev->dev_reservation_lock); |
104 | return -EINVAL; | 104 | return -EINVAL; |
105 | } | 105 | } |
106 | if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) { | 106 | if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) { |
107 | spin_unlock(&dev->dev_reservation_lock); | 107 | spin_unlock(&dev->dev_reservation_lock); |
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -EINVAL; | 110 | ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -EINVAL; |
111 | spin_unlock(&dev->dev_reservation_lock); | 111 | spin_unlock(&dev->dev_reservation_lock); |
112 | 112 | ||
113 | return ret; | 113 | return ret; |
114 | } | 114 | } |
115 | 115 | ||
116 | static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, | 116 | static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, |
117 | struct se_node_acl *, struct se_session *); | 117 | struct se_node_acl *, struct se_session *); |
118 | static void core_scsi3_put_pr_reg(struct t10_pr_registration *); | 118 | static void core_scsi3_put_pr_reg(struct t10_pr_registration *); |
119 | 119 | ||
120 | static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) | 120 | static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) |
121 | { | 121 | { |
122 | struct se_session *se_sess = cmd->se_sess; | 122 | struct se_session *se_sess = cmd->se_sess; |
123 | struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; | 123 | struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; |
124 | struct t10_pr_registration *pr_reg; | 124 | struct t10_pr_registration *pr_reg; |
125 | struct t10_reservation *pr_tmpl = &su_dev->t10_pr; | 125 | struct t10_reservation *pr_tmpl = &su_dev->t10_pr; |
126 | int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); | 126 | int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); |
127 | int conflict = 0; | 127 | int conflict = 0; |
128 | 128 | ||
129 | if (!crh) | 129 | if (!crh) |
130 | return false; | 130 | return false; |
131 | 131 | ||
132 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, | 132 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, |
133 | se_sess); | 133 | se_sess); |
134 | if (pr_reg) { | 134 | if (pr_reg) { |
135 | /* | 135 | /* |
136 | * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE | 136 | * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE |
137 | * behavior | 137 | * behavior |
138 | * | 138 | * |
139 | * A RESERVE(6) or RESERVE(10) command shall complete with GOOD | 139 | * A RESERVE(6) or RESERVE(10) command shall complete with GOOD |
140 | * status, but no reservation shall be established and the | 140 | * status, but no reservation shall be established and the |
141 | * persistent reservation shall not be changed, if the command | 141 | * persistent reservation shall not be changed, if the command |
142 | * is received from a) and b) below. | 142 | * is received from a) and b) below. |
143 | * | 143 | * |
144 | * A RELEASE(6) or RELEASE(10) command shall complete with GOOD | 144 | * A RELEASE(6) or RELEASE(10) command shall complete with GOOD |
145 | * status, but the persistent reservation shall not be released, | 145 | * status, but the persistent reservation shall not be released, |
146 | * if the command is received from a) and b) | 146 | * if the command is received from a) and b) |
147 | * | 147 | * |
148 | * a) An I_T nexus that is a persistent reservation holder; or | 148 | * a) An I_T nexus that is a persistent reservation holder; or |
149 | * b) An I_T nexus that is registered if a registrants only or | 149 | * b) An I_T nexus that is registered if a registrants only or |
150 | * all registrants type persistent reservation is present. | 150 | * all registrants type persistent reservation is present. |
151 | * | 151 | * |
152 | * In all other cases, a RESERVE(6) command, RESERVE(10) command, | 152 | * In all other cases, a RESERVE(6) command, RESERVE(10) command, |
153 | * RELEASE(6) command, or RELEASE(10) command shall be processed | 153 | * RELEASE(6) command, or RELEASE(10) command shall be processed |
154 | * as defined in SPC-2. | 154 | * as defined in SPC-2. |
155 | */ | 155 | */ |
156 | if (pr_reg->pr_res_holder) { | 156 | if (pr_reg->pr_res_holder) { |
157 | core_scsi3_put_pr_reg(pr_reg); | 157 | core_scsi3_put_pr_reg(pr_reg); |
158 | *ret = 0; | 158 | *ret = 0; |
159 | return false; | 159 | return false; |
160 | } | 160 | } |
161 | if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || | 161 | if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || |
162 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || | 162 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || |
163 | (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | 163 | (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || |
164 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { | 164 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { |
165 | core_scsi3_put_pr_reg(pr_reg); | 165 | core_scsi3_put_pr_reg(pr_reg); |
166 | *ret = 0; | 166 | *ret = 0; |
167 | return true; | 167 | return true; |
168 | } | 168 | } |
169 | core_scsi3_put_pr_reg(pr_reg); | 169 | core_scsi3_put_pr_reg(pr_reg); |
170 | conflict = 1; | 170 | conflict = 1; |
171 | } else { | 171 | } else { |
172 | /* | 172 | /* |
173 | * Following spc2r20 5.5.1 Reservations overview: | 173 | * Following spc2r20 5.5.1 Reservations overview: |
174 | * | 174 | * |
175 | * If a logical unit has executed a PERSISTENT RESERVE OUT | 175 | * If a logical unit has executed a PERSISTENT RESERVE OUT |
176 | * command with the REGISTER or the REGISTER AND IGNORE | 176 | * command with the REGISTER or the REGISTER AND IGNORE |
177 | * EXISTING KEY service action and is still registered by any | 177 | * EXISTING KEY service action and is still registered by any |
178 | * initiator, all RESERVE commands and all RELEASE commands | 178 | * initiator, all RESERVE commands and all RELEASE commands |
179 | * regardless of initiator shall conflict and shall terminate | 179 | * regardless of initiator shall conflict and shall terminate |
180 | * with a RESERVATION CONFLICT status. | 180 | * with a RESERVATION CONFLICT status. |
181 | */ | 181 | */ |
182 | spin_lock(&pr_tmpl->registration_lock); | 182 | spin_lock(&pr_tmpl->registration_lock); |
183 | conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; | 183 | conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; |
184 | spin_unlock(&pr_tmpl->registration_lock); | 184 | spin_unlock(&pr_tmpl->registration_lock); |
185 | } | 185 | } |
186 | 186 | ||
187 | if (conflict) { | 187 | if (conflict) { |
188 | pr_err("Received legacy SPC-2 RESERVE/RELEASE" | 188 | pr_err("Received legacy SPC-2 RESERVE/RELEASE" |
189 | " while active SPC-3 registrations exist," | 189 | " while active SPC-3 registrations exist," |
190 | " returning RESERVATION_CONFLICT\n"); | 190 | " returning RESERVATION_CONFLICT\n"); |
191 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 191 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
192 | return true; | 192 | return true; |
193 | } | 193 | } |
194 | 194 | ||
195 | return false; | 195 | return false; |
196 | } | 196 | } |
197 | 197 | ||
198 | int target_scsi2_reservation_release(struct se_task *task) | 198 | int target_scsi2_reservation_release(struct se_task *task) |
199 | { | 199 | { |
200 | struct se_cmd *cmd = task->task_se_cmd; | 200 | struct se_cmd *cmd = task->task_se_cmd; |
201 | struct se_device *dev = cmd->se_dev; | 201 | struct se_device *dev = cmd->se_dev; |
202 | struct se_session *sess = cmd->se_sess; | 202 | struct se_session *sess = cmd->se_sess; |
203 | struct se_portal_group *tpg = sess->se_tpg; | 203 | struct se_portal_group *tpg = sess->se_tpg; |
204 | int ret = 0; | 204 | int ret = 0; |
205 | 205 | ||
206 | if (!sess || !tpg) | 206 | if (!sess || !tpg) |
207 | goto out; | 207 | goto out; |
208 | if (target_check_scsi2_reservation_conflict(cmd, &ret)) | 208 | if (target_check_scsi2_reservation_conflict(cmd, &ret)) |
209 | goto out; | 209 | goto out; |
210 | 210 | ||
211 | ret = 0; | 211 | ret = 0; |
212 | spin_lock(&dev->dev_reservation_lock); | 212 | spin_lock(&dev->dev_reservation_lock); |
213 | if (!dev->dev_reserved_node_acl || !sess) | 213 | if (!dev->dev_reserved_node_acl || !sess) |
214 | goto out_unlock; | 214 | goto out_unlock; |
215 | 215 | ||
216 | if (dev->dev_reserved_node_acl != sess->se_node_acl) | 216 | if (dev->dev_reserved_node_acl != sess->se_node_acl) |
217 | goto out_unlock; | 217 | goto out_unlock; |
218 | 218 | ||
219 | dev->dev_reserved_node_acl = NULL; | 219 | dev->dev_reserved_node_acl = NULL; |
220 | dev->dev_flags &= ~DF_SPC2_RESERVATIONS; | 220 | dev->dev_flags &= ~DF_SPC2_RESERVATIONS; |
221 | if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { | 221 | if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { |
222 | dev->dev_res_bin_isid = 0; | 222 | dev->dev_res_bin_isid = 0; |
223 | dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; | 223 | dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; |
224 | } | 224 | } |
225 | pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" | 225 | pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" |
226 | " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), | 226 | " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), |
227 | cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, | 227 | cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, |
228 | sess->se_node_acl->initiatorname); | 228 | sess->se_node_acl->initiatorname); |
229 | 229 | ||
230 | out_unlock: | 230 | out_unlock: |
231 | spin_unlock(&dev->dev_reservation_lock); | 231 | spin_unlock(&dev->dev_reservation_lock); |
232 | out: | 232 | out: |
233 | if (!ret) { | 233 | if (!ret) { |
234 | task->task_scsi_status = GOOD; | 234 | task->task_scsi_status = GOOD; |
235 | transport_complete_task(task, 1); | 235 | transport_complete_task(task, 1); |
236 | } | 236 | } |
237 | return ret; | 237 | return ret; |
238 | } | 238 | } |
239 | 239 | ||
240 | int target_scsi2_reservation_reserve(struct se_task *task) | 240 | int target_scsi2_reservation_reserve(struct se_task *task) |
241 | { | 241 | { |
242 | struct se_cmd *cmd = task->task_se_cmd; | 242 | struct se_cmd *cmd = task->task_se_cmd; |
243 | struct se_device *dev = cmd->se_dev; | 243 | struct se_device *dev = cmd->se_dev; |
244 | struct se_session *sess = cmd->se_sess; | 244 | struct se_session *sess = cmd->se_sess; |
245 | struct se_portal_group *tpg = sess->se_tpg; | 245 | struct se_portal_group *tpg = sess->se_tpg; |
246 | int ret = 0; | 246 | int ret = 0; |
247 | 247 | ||
248 | if ((cmd->t_task_cdb[1] & 0x01) && | 248 | if ((cmd->t_task_cdb[1] & 0x01) && |
249 | (cmd->t_task_cdb[1] & 0x02)) { | 249 | (cmd->t_task_cdb[1] & 0x02)) { |
250 | pr_err("LongIO and Obselete Bits set, returning" | 250 | pr_err("LongIO and Obselete Bits set, returning" |
251 | " ILLEGAL_REQUEST\n"); | 251 | " ILLEGAL_REQUEST\n"); |
252 | cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; | 252 | cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; |
253 | ret = -EINVAL; | 253 | ret = -EINVAL; |
254 | goto out; | 254 | goto out; |
255 | } | 255 | } |
256 | /* | 256 | /* |
257 | * This is currently the case for target_core_mod passthrough struct se_cmd | 257 | * This is currently the case for target_core_mod passthrough struct se_cmd |
258 | * ops | 258 | * ops |
259 | */ | 259 | */ |
260 | if (!sess || !tpg) | 260 | if (!sess || !tpg) |
261 | goto out; | 261 | goto out; |
262 | if (target_check_scsi2_reservation_conflict(cmd, &ret)) | 262 | if (target_check_scsi2_reservation_conflict(cmd, &ret)) |
263 | goto out; | 263 | goto out; |
264 | 264 | ||
265 | ret = 0; | 265 | ret = 0; |
266 | spin_lock(&dev->dev_reservation_lock); | 266 | spin_lock(&dev->dev_reservation_lock); |
267 | if (dev->dev_reserved_node_acl && | 267 | if (dev->dev_reserved_node_acl && |
268 | (dev->dev_reserved_node_acl != sess->se_node_acl)) { | 268 | (dev->dev_reserved_node_acl != sess->se_node_acl)) { |
269 | pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", | 269 | pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", |
270 | tpg->se_tpg_tfo->get_fabric_name()); | 270 | tpg->se_tpg_tfo->get_fabric_name()); |
271 | pr_err("Original reserver LUN: %u %s\n", | 271 | pr_err("Original reserver LUN: %u %s\n", |
272 | cmd->se_lun->unpacked_lun, | 272 | cmd->se_lun->unpacked_lun, |
273 | dev->dev_reserved_node_acl->initiatorname); | 273 | dev->dev_reserved_node_acl->initiatorname); |
274 | pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" | 274 | pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" |
275 | " from %s \n", cmd->se_lun->unpacked_lun, | 275 | " from %s \n", cmd->se_lun->unpacked_lun, |
276 | cmd->se_deve->mapped_lun, | 276 | cmd->se_deve->mapped_lun, |
277 | sess->se_node_acl->initiatorname); | 277 | sess->se_node_acl->initiatorname); |
278 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 278 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
279 | ret = -EINVAL; | 279 | ret = -EINVAL; |
280 | goto out_unlock; | 280 | goto out_unlock; |
281 | } | 281 | } |
282 | 282 | ||
283 | dev->dev_reserved_node_acl = sess->se_node_acl; | 283 | dev->dev_reserved_node_acl = sess->se_node_acl; |
284 | dev->dev_flags |= DF_SPC2_RESERVATIONS; | 284 | dev->dev_flags |= DF_SPC2_RESERVATIONS; |
285 | if (sess->sess_bin_isid != 0) { | 285 | if (sess->sess_bin_isid != 0) { |
286 | dev->dev_res_bin_isid = sess->sess_bin_isid; | 286 | dev->dev_res_bin_isid = sess->sess_bin_isid; |
287 | dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; | 287 | dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; |
288 | } | 288 | } |
289 | pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" | 289 | pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" |
290 | " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), | 290 | " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), |
291 | cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, | 291 | cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, |
292 | sess->se_node_acl->initiatorname); | 292 | sess->se_node_acl->initiatorname); |
293 | 293 | ||
294 | out_unlock: | 294 | out_unlock: |
295 | spin_unlock(&dev->dev_reservation_lock); | 295 | spin_unlock(&dev->dev_reservation_lock); |
296 | out: | 296 | out: |
297 | if (!ret) { | 297 | if (!ret) { |
298 | task->task_scsi_status = GOOD; | 298 | task->task_scsi_status = GOOD; |
299 | transport_complete_task(task, 1); | 299 | transport_complete_task(task, 1); |
300 | } | 300 | } |
301 | return ret; | 301 | return ret; |
302 | } | 302 | } |
303 | 303 | ||
304 | 304 | ||
305 | /* | 305 | /* |
306 | * Begin SPC-3/SPC-4 Persistent Reservations emulation support | 306 | * Begin SPC-3/SPC-4 Persistent Reservations emulation support |
307 | * | 307 | * |
308 | * This function is called by those initiator ports who are *NOT* | 308 | * This function is called by those initiator ports who are *NOT* |
309 | * the active PR reservation holder when a reservation is present. | 309 | * the active PR reservation holder when a reservation is present. |
310 | */ | 310 | */ |
311 | static int core_scsi3_pr_seq_non_holder( | 311 | static int core_scsi3_pr_seq_non_holder( |
312 | struct se_cmd *cmd, | 312 | struct se_cmd *cmd, |
313 | unsigned char *cdb, | 313 | unsigned char *cdb, |
314 | u32 pr_reg_type) | 314 | u32 pr_reg_type) |
315 | { | 315 | { |
316 | struct se_dev_entry *se_deve; | 316 | struct se_dev_entry *se_deve; |
317 | struct se_session *se_sess = cmd->se_sess; | 317 | struct se_session *se_sess = cmd->se_sess; |
318 | int other_cdb = 0, ignore_reg; | 318 | int other_cdb = 0, ignore_reg; |
319 | int registered_nexus = 0, ret = 1; /* Conflict by default */ | 319 | int registered_nexus = 0, ret = 1; /* Conflict by default */ |
320 | int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */ | 320 | int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */ |
321 | int we = 0; /* Write Exclusive */ | 321 | int we = 0; /* Write Exclusive */ |
322 | int legacy = 0; /* Act like a legacy device and return | 322 | int legacy = 0; /* Act like a legacy device and return |
323 | * RESERVATION CONFLICT on some CDBs */ | 323 | * RESERVATION CONFLICT on some CDBs */ |
324 | /* | 324 | /* |
325 | * A legacy SPC-2 reservation is being held. | 325 | * A legacy SPC-2 reservation is being held. |
326 | */ | 326 | */ |
327 | if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) | 327 | if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) |
328 | return core_scsi2_reservation_seq_non_holder(cmd, | 328 | return core_scsi2_reservation_seq_non_holder(cmd, |
329 | cdb, pr_reg_type); | 329 | cdb, pr_reg_type); |
330 | 330 | ||
331 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; | 331 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; |
332 | /* | 332 | /* |
333 | * Determine if the registration should be ignored due to | 333 | * Determine if the registration should be ignored due to |
334 | * non-matching ISIDs in core_scsi3_pr_reservation_check(). | 334 | * non-matching ISIDs in core_scsi3_pr_reservation_check(). |
335 | */ | 335 | */ |
336 | ignore_reg = (pr_reg_type & 0x80000000); | 336 | ignore_reg = (pr_reg_type & 0x80000000); |
337 | if (ignore_reg) | 337 | if (ignore_reg) |
338 | pr_reg_type &= ~0x80000000; | 338 | pr_reg_type &= ~0x80000000; |
339 | 339 | ||
340 | switch (pr_reg_type) { | 340 | switch (pr_reg_type) { |
341 | case PR_TYPE_WRITE_EXCLUSIVE: | 341 | case PR_TYPE_WRITE_EXCLUSIVE: |
342 | we = 1; | 342 | we = 1; |
343 | case PR_TYPE_EXCLUSIVE_ACCESS: | 343 | case PR_TYPE_EXCLUSIVE_ACCESS: |
344 | /* | 344 | /* |
345 | * Some commands are only allowed for the persistent reservation | 345 | * Some commands are only allowed for the persistent reservation |
346 | * holder. | 346 | * holder. |
347 | */ | 347 | */ |
348 | if ((se_deve->def_pr_registered) && !(ignore_reg)) | 348 | if ((se_deve->def_pr_registered) && !(ignore_reg)) |
349 | registered_nexus = 1; | 349 | registered_nexus = 1; |
350 | break; | 350 | break; |
351 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: | 351 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: |
352 | we = 1; | 352 | we = 1; |
353 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: | 353 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: |
354 | /* | 354 | /* |
355 | * Some commands are only allowed for registered I_T Nexuses. | 355 | * Some commands are only allowed for registered I_T Nexuses. |
356 | */ | 356 | */ |
357 | reg_only = 1; | 357 | reg_only = 1; |
358 | if ((se_deve->def_pr_registered) && !(ignore_reg)) | 358 | if ((se_deve->def_pr_registered) && !(ignore_reg)) |
359 | registered_nexus = 1; | 359 | registered_nexus = 1; |
360 | break; | 360 | break; |
361 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: | 361 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: |
362 | we = 1; | 362 | we = 1; |
363 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: | 363 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: |
364 | /* | 364 | /* |
365 | * Each registered I_T Nexus is a reservation holder. | 365 | * Each registered I_T Nexus is a reservation holder. |
366 | */ | 366 | */ |
367 | all_reg = 1; | 367 | all_reg = 1; |
368 | if ((se_deve->def_pr_registered) && !(ignore_reg)) | 368 | if ((se_deve->def_pr_registered) && !(ignore_reg)) |
369 | registered_nexus = 1; | 369 | registered_nexus = 1; |
370 | break; | 370 | break; |
371 | default: | 371 | default: |
372 | return -EINVAL; | 372 | return -EINVAL; |
373 | } | 373 | } |
374 | /* | 374 | /* |
375 | * Referenced from spc4r17 table 45 for *NON* PR holder access | 375 | * Referenced from spc4r17 table 45 for *NON* PR holder access |
376 | */ | 376 | */ |
377 | switch (cdb[0]) { | 377 | switch (cdb[0]) { |
378 | case SECURITY_PROTOCOL_IN: | 378 | case SECURITY_PROTOCOL_IN: |
379 | if (registered_nexus) | 379 | if (registered_nexus) |
380 | return 0; | 380 | return 0; |
381 | ret = (we) ? 0 : 1; | 381 | ret = (we) ? 0 : 1; |
382 | break; | 382 | break; |
383 | case MODE_SENSE: | 383 | case MODE_SENSE: |
384 | case MODE_SENSE_10: | 384 | case MODE_SENSE_10: |
385 | case READ_ATTRIBUTE: | 385 | case READ_ATTRIBUTE: |
386 | case READ_BUFFER: | 386 | case READ_BUFFER: |
387 | case RECEIVE_DIAGNOSTIC: | 387 | case RECEIVE_DIAGNOSTIC: |
388 | if (legacy) { | 388 | if (legacy) { |
389 | ret = 1; | 389 | ret = 1; |
390 | break; | 390 | break; |
391 | } | 391 | } |
392 | if (registered_nexus) { | 392 | if (registered_nexus) { |
393 | ret = 0; | 393 | ret = 0; |
394 | break; | 394 | break; |
395 | } | 395 | } |
396 | ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ | 396 | ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ |
397 | break; | 397 | break; |
398 | case PERSISTENT_RESERVE_OUT: | 398 | case PERSISTENT_RESERVE_OUT: |
399 | /* | 399 | /* |
400 | * This follows PERSISTENT_RESERVE_OUT service actions that | 400 | * This follows PERSISTENT_RESERVE_OUT service actions that |
401 | * are allowed in the presence of various reservations. | 401 | * are allowed in the presence of various reservations. |
402 | * See spc4r17, table 46 | 402 | * See spc4r17, table 46 |
403 | */ | 403 | */ |
404 | switch (cdb[1] & 0x1f) { | 404 | switch (cdb[1] & 0x1f) { |
405 | case PRO_CLEAR: | 405 | case PRO_CLEAR: |
406 | case PRO_PREEMPT: | 406 | case PRO_PREEMPT: |
407 | case PRO_PREEMPT_AND_ABORT: | 407 | case PRO_PREEMPT_AND_ABORT: |
408 | ret = (registered_nexus) ? 0 : 1; | 408 | ret = (registered_nexus) ? 0 : 1; |
409 | break; | 409 | break; |
410 | case PRO_REGISTER: | 410 | case PRO_REGISTER: |
411 | case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: | 411 | case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: |
412 | ret = 0; | 412 | ret = 0; |
413 | break; | 413 | break; |
414 | case PRO_REGISTER_AND_MOVE: | 414 | case PRO_REGISTER_AND_MOVE: |
415 | case PRO_RESERVE: | 415 | case PRO_RESERVE: |
416 | ret = 1; | 416 | ret = 1; |
417 | break; | 417 | break; |
418 | case PRO_RELEASE: | 418 | case PRO_RELEASE: |
419 | ret = (registered_nexus) ? 0 : 1; | 419 | ret = (registered_nexus) ? 0 : 1; |
420 | break; | 420 | break; |
421 | default: | 421 | default: |
422 | pr_err("Unknown PERSISTENT_RESERVE_OUT service" | 422 | pr_err("Unknown PERSISTENT_RESERVE_OUT service" |
423 | " action: 0x%02x\n", cdb[1] & 0x1f); | 423 | " action: 0x%02x\n", cdb[1] & 0x1f); |
424 | return -EINVAL; | 424 | return -EINVAL; |
425 | } | 425 | } |
426 | break; | 426 | break; |
427 | case RELEASE: | 427 | case RELEASE: |
428 | case RELEASE_10: | 428 | case RELEASE_10: |
429 | /* Handled by CRH=1 in target_scsi2_reservation_release() */ | 429 | /* Handled by CRH=1 in target_scsi2_reservation_release() */ |
430 | ret = 0; | 430 | ret = 0; |
431 | break; | 431 | break; |
432 | case RESERVE: | 432 | case RESERVE: |
433 | case RESERVE_10: | 433 | case RESERVE_10: |
434 | /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ | 434 | /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ |
435 | ret = 0; | 435 | ret = 0; |
436 | break; | 436 | break; |
437 | case TEST_UNIT_READY: | 437 | case TEST_UNIT_READY: |
438 | ret = (legacy) ? 1 : 0; /* Conflict for legacy */ | 438 | ret = (legacy) ? 1 : 0; /* Conflict for legacy */ |
439 | break; | 439 | break; |
440 | case MAINTENANCE_IN: | 440 | case MAINTENANCE_IN: |
441 | switch (cdb[1] & 0x1f) { | 441 | switch (cdb[1] & 0x1f) { |
442 | case MI_MANAGEMENT_PROTOCOL_IN: | 442 | case MI_MANAGEMENT_PROTOCOL_IN: |
443 | if (registered_nexus) { | 443 | if (registered_nexus) { |
444 | ret = 0; | 444 | ret = 0; |
445 | break; | 445 | break; |
446 | } | 446 | } |
447 | ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ | 447 | ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ |
448 | break; | 448 | break; |
449 | case MI_REPORT_SUPPORTED_OPERATION_CODES: | 449 | case MI_REPORT_SUPPORTED_OPERATION_CODES: |
450 | case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS: | 450 | case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS: |
451 | if (legacy) { | 451 | if (legacy) { |
452 | ret = 1; | 452 | ret = 1; |
453 | break; | 453 | break; |
454 | } | 454 | } |
455 | if (registered_nexus) { | 455 | if (registered_nexus) { |
456 | ret = 0; | 456 | ret = 0; |
457 | break; | 457 | break; |
458 | } | 458 | } |
459 | ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ | 459 | ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ |
460 | break; | 460 | break; |
461 | case MI_REPORT_ALIASES: | 461 | case MI_REPORT_ALIASES: |
462 | case MI_REPORT_IDENTIFYING_INFORMATION: | 462 | case MI_REPORT_IDENTIFYING_INFORMATION: |
463 | case MI_REPORT_PRIORITY: | 463 | case MI_REPORT_PRIORITY: |
464 | case MI_REPORT_TARGET_PGS: | 464 | case MI_REPORT_TARGET_PGS: |
465 | case MI_REPORT_TIMESTAMP: | 465 | case MI_REPORT_TIMESTAMP: |
466 | ret = 0; /* Allowed */ | 466 | ret = 0; /* Allowed */ |
467 | break; | 467 | break; |
468 | default: | 468 | default: |
469 | pr_err("Unknown MI Service Action: 0x%02x\n", | 469 | pr_err("Unknown MI Service Action: 0x%02x\n", |
470 | (cdb[1] & 0x1f)); | 470 | (cdb[1] & 0x1f)); |
471 | return -EINVAL; | 471 | return -EINVAL; |
472 | } | 472 | } |
473 | break; | 473 | break; |
474 | case ACCESS_CONTROL_IN: | 474 | case ACCESS_CONTROL_IN: |
475 | case ACCESS_CONTROL_OUT: | 475 | case ACCESS_CONTROL_OUT: |
476 | case INQUIRY: | 476 | case INQUIRY: |
477 | case LOG_SENSE: | 477 | case LOG_SENSE: |
478 | case READ_MEDIA_SERIAL_NUMBER: | 478 | case READ_MEDIA_SERIAL_NUMBER: |
479 | case REPORT_LUNS: | 479 | case REPORT_LUNS: |
480 | case REQUEST_SENSE: | 480 | case REQUEST_SENSE: |
481 | case PERSISTENT_RESERVE_IN: | 481 | case PERSISTENT_RESERVE_IN: |
482 | ret = 0; /*/ Allowed CDBs */ | 482 | ret = 0; /*/ Allowed CDBs */ |
483 | break; | 483 | break; |
484 | default: | 484 | default: |
485 | other_cdb = 1; | 485 | other_cdb = 1; |
486 | break; | 486 | break; |
487 | } | 487 | } |
488 | /* | 488 | /* |
489 | * Case where the CDB is explicitly allowed in the above switch | 489 | * Case where the CDB is explicitly allowed in the above switch |
490 | * statement. | 490 | * statement. |
491 | */ | 491 | */ |
492 | if (!ret && !other_cdb) { | 492 | if (!ret && !other_cdb) { |
493 | #if 0 | 493 | #if 0 |
494 | pr_debug("Allowing explict CDB: 0x%02x for %s" | 494 | pr_debug("Allowing explict CDB: 0x%02x for %s" |
495 | " reservation holder\n", cdb[0], | 495 | " reservation holder\n", cdb[0], |
496 | core_scsi3_pr_dump_type(pr_reg_type)); | 496 | core_scsi3_pr_dump_type(pr_reg_type)); |
497 | #endif | 497 | #endif |
498 | return ret; | 498 | return ret; |
499 | } | 499 | } |
500 | /* | 500 | /* |
501 | * Check if write exclusive initiator ports *NOT* holding the | 501 | * Check if write exclusive initiator ports *NOT* holding the |
502 | * WRITE_EXCLUSIVE_* reservation. | 502 | * WRITE_EXCLUSIVE_* reservation. |
503 | */ | 503 | */ |
504 | if ((we) && !(registered_nexus)) { | 504 | if ((we) && !(registered_nexus)) { |
505 | if (cmd->data_direction == DMA_TO_DEVICE) { | 505 | if (cmd->data_direction == DMA_TO_DEVICE) { |
506 | /* | 506 | /* |
507 | * Conflict for write exclusive | 507 | * Conflict for write exclusive |
508 | */ | 508 | */ |
509 | pr_debug("%s Conflict for unregistered nexus" | 509 | pr_debug("%s Conflict for unregistered nexus" |
510 | " %s CDB: 0x%02x to %s reservation\n", | 510 | " %s CDB: 0x%02x to %s reservation\n", |
511 | transport_dump_cmd_direction(cmd), | 511 | transport_dump_cmd_direction(cmd), |
512 | se_sess->se_node_acl->initiatorname, cdb[0], | 512 | se_sess->se_node_acl->initiatorname, cdb[0], |
513 | core_scsi3_pr_dump_type(pr_reg_type)); | 513 | core_scsi3_pr_dump_type(pr_reg_type)); |
514 | return 1; | 514 | return 1; |
515 | } else { | 515 | } else { |
516 | /* | 516 | /* |
517 | * Allow non WRITE CDBs for all Write Exclusive | 517 | * Allow non WRITE CDBs for all Write Exclusive |
518 | * PR TYPEs to pass for registered and | 518 | * PR TYPEs to pass for registered and |
519 | * non-registered_nexuxes NOT holding the reservation. | 519 | * non-registered_nexuxes NOT holding the reservation. |
520 | * | 520 | * |
521 | * We only make noise for the unregisterd nexuses, | 521 | * We only make noise for the unregisterd nexuses, |
522 | * as we expect registered non-reservation holding | 522 | * as we expect registered non-reservation holding |
523 | * nexuses to issue CDBs. | 523 | * nexuses to issue CDBs. |
524 | */ | 524 | */ |
525 | #if 0 | 525 | #if 0 |
526 | if (!registered_nexus) { | 526 | if (!registered_nexus) { |
527 | pr_debug("Allowing implict CDB: 0x%02x" | 527 | pr_debug("Allowing implict CDB: 0x%02x" |
528 | " for %s reservation on unregistered" | 528 | " for %s reservation on unregistered" |
529 | " nexus\n", cdb[0], | 529 | " nexus\n", cdb[0], |
530 | core_scsi3_pr_dump_type(pr_reg_type)); | 530 | core_scsi3_pr_dump_type(pr_reg_type)); |
531 | } | 531 | } |
532 | #endif | 532 | #endif |
533 | return 0; | 533 | return 0; |
534 | } | 534 | } |
535 | } else if ((reg_only) || (all_reg)) { | 535 | } else if ((reg_only) || (all_reg)) { |
536 | if (registered_nexus) { | 536 | if (registered_nexus) { |
537 | /* | 537 | /* |
538 | * For PR_*_REG_ONLY and PR_*_ALL_REG reservations, | 538 | * For PR_*_REG_ONLY and PR_*_ALL_REG reservations, |
539 | * allow commands from registered nexuses. | 539 | * allow commands from registered nexuses. |
540 | */ | 540 | */ |
541 | #if 0 | 541 | #if 0 |
542 | pr_debug("Allowing implict CDB: 0x%02x for %s" | 542 | pr_debug("Allowing implict CDB: 0x%02x for %s" |
543 | " reservation\n", cdb[0], | 543 | " reservation\n", cdb[0], |
544 | core_scsi3_pr_dump_type(pr_reg_type)); | 544 | core_scsi3_pr_dump_type(pr_reg_type)); |
545 | #endif | 545 | #endif |
546 | return 0; | 546 | return 0; |
547 | } | 547 | } |
548 | } | 548 | } |
549 | pr_debug("%s Conflict for %sregistered nexus %s CDB: 0x%2x" | 549 | pr_debug("%s Conflict for %sregistered nexus %s CDB: 0x%2x" |
550 | " for %s reservation\n", transport_dump_cmd_direction(cmd), | 550 | " for %s reservation\n", transport_dump_cmd_direction(cmd), |
551 | (registered_nexus) ? "" : "un", | 551 | (registered_nexus) ? "" : "un", |
552 | se_sess->se_node_acl->initiatorname, cdb[0], | 552 | se_sess->se_node_acl->initiatorname, cdb[0], |
553 | core_scsi3_pr_dump_type(pr_reg_type)); | 553 | core_scsi3_pr_dump_type(pr_reg_type)); |
554 | 554 | ||
555 | return 1; /* Conflict by default */ | 555 | return 1; /* Conflict by default */ |
556 | } | 556 | } |
557 | 557 | ||
558 | static u32 core_scsi3_pr_generation(struct se_device *dev) | 558 | static u32 core_scsi3_pr_generation(struct se_device *dev) |
559 | { | 559 | { |
560 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; | 560 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; |
561 | u32 prg; | 561 | u32 prg; |
562 | /* | 562 | /* |
563 | * PRGeneration field shall contain the value of a 32-bit wrapping | 563 | * PRGeneration field shall contain the value of a 32-bit wrapping |
564 | * counter mainted by the device server. | 564 | * counter mainted by the device server. |
565 | * | 565 | * |
566 | * Note that this is done regardless of Active Persist across | 566 | * Note that this is done regardless of Active Persist across |
567 | * Target PowerLoss (APTPL) | 567 | * Target PowerLoss (APTPL) |
568 | * | 568 | * |
569 | * See spc4r17 section 6.3.12 READ_KEYS service action | 569 | * See spc4r17 section 6.3.12 READ_KEYS service action |
570 | */ | 570 | */ |
571 | spin_lock(&dev->dev_reservation_lock); | 571 | spin_lock(&dev->dev_reservation_lock); |
572 | prg = su_dev->t10_pr.pr_generation++; | 572 | prg = su_dev->t10_pr.pr_generation++; |
573 | spin_unlock(&dev->dev_reservation_lock); | 573 | spin_unlock(&dev->dev_reservation_lock); |
574 | 574 | ||
575 | return prg; | 575 | return prg; |
576 | } | 576 | } |
577 | 577 | ||
578 | static int core_scsi3_pr_reservation_check( | 578 | static int core_scsi3_pr_reservation_check( |
579 | struct se_cmd *cmd, | 579 | struct se_cmd *cmd, |
580 | u32 *pr_reg_type) | 580 | u32 *pr_reg_type) |
581 | { | 581 | { |
582 | struct se_device *dev = cmd->se_dev; | 582 | struct se_device *dev = cmd->se_dev; |
583 | struct se_session *sess = cmd->se_sess; | 583 | struct se_session *sess = cmd->se_sess; |
584 | int ret; | 584 | int ret; |
585 | 585 | ||
586 | if (!sess) | 586 | if (!sess) |
587 | return 0; | 587 | return 0; |
588 | /* | 588 | /* |
589 | * A legacy SPC-2 reservation is being held. | 589 | * A legacy SPC-2 reservation is being held. |
590 | */ | 590 | */ |
591 | if (dev->dev_flags & DF_SPC2_RESERVATIONS) | 591 | if (dev->dev_flags & DF_SPC2_RESERVATIONS) |
592 | return core_scsi2_reservation_check(cmd, pr_reg_type); | 592 | return core_scsi2_reservation_check(cmd, pr_reg_type); |
593 | 593 | ||
594 | spin_lock(&dev->dev_reservation_lock); | 594 | spin_lock(&dev->dev_reservation_lock); |
595 | if (!dev->dev_pr_res_holder) { | 595 | if (!dev->dev_pr_res_holder) { |
596 | spin_unlock(&dev->dev_reservation_lock); | 596 | spin_unlock(&dev->dev_reservation_lock); |
597 | return 0; | 597 | return 0; |
598 | } | 598 | } |
599 | *pr_reg_type = dev->dev_pr_res_holder->pr_res_type; | 599 | *pr_reg_type = dev->dev_pr_res_holder->pr_res_type; |
600 | cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; | 600 | cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; |
601 | if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) { | 601 | if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) { |
602 | spin_unlock(&dev->dev_reservation_lock); | 602 | spin_unlock(&dev->dev_reservation_lock); |
603 | return -EINVAL; | 603 | return -EINVAL; |
604 | } | 604 | } |
605 | if (!dev->dev_pr_res_holder->isid_present_at_reg) { | 605 | if (!dev->dev_pr_res_holder->isid_present_at_reg) { |
606 | spin_unlock(&dev->dev_reservation_lock); | 606 | spin_unlock(&dev->dev_reservation_lock); |
607 | return 0; | 607 | return 0; |
608 | } | 608 | } |
609 | ret = (dev->dev_pr_res_holder->pr_reg_bin_isid == | 609 | ret = (dev->dev_pr_res_holder->pr_reg_bin_isid == |
610 | sess->sess_bin_isid) ? 0 : -EINVAL; | 610 | sess->sess_bin_isid) ? 0 : -EINVAL; |
611 | /* | 611 | /* |
612 | * Use bit in *pr_reg_type to notify ISID mismatch in | 612 | * Use bit in *pr_reg_type to notify ISID mismatch in |
613 | * core_scsi3_pr_seq_non_holder(). | 613 | * core_scsi3_pr_seq_non_holder(). |
614 | */ | 614 | */ |
615 | if (ret != 0) | 615 | if (ret != 0) |
616 | *pr_reg_type |= 0x80000000; | 616 | *pr_reg_type |= 0x80000000; |
617 | spin_unlock(&dev->dev_reservation_lock); | 617 | spin_unlock(&dev->dev_reservation_lock); |
618 | 618 | ||
619 | return ret; | 619 | return ret; |
620 | } | 620 | } |
621 | 621 | ||
622 | static struct t10_pr_registration *__core_scsi3_do_alloc_registration( | 622 | static struct t10_pr_registration *__core_scsi3_do_alloc_registration( |
623 | struct se_device *dev, | 623 | struct se_device *dev, |
624 | struct se_node_acl *nacl, | 624 | struct se_node_acl *nacl, |
625 | struct se_dev_entry *deve, | 625 | struct se_dev_entry *deve, |
626 | unsigned char *isid, | 626 | unsigned char *isid, |
627 | u64 sa_res_key, | 627 | u64 sa_res_key, |
628 | int all_tg_pt, | 628 | int all_tg_pt, |
629 | int aptpl) | 629 | int aptpl) |
630 | { | 630 | { |
631 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; | 631 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; |
632 | struct t10_pr_registration *pr_reg; | 632 | struct t10_pr_registration *pr_reg; |
633 | 633 | ||
634 | pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC); | 634 | pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC); |
635 | if (!pr_reg) { | 635 | if (!pr_reg) { |
636 | pr_err("Unable to allocate struct t10_pr_registration\n"); | 636 | pr_err("Unable to allocate struct t10_pr_registration\n"); |
637 | return NULL; | 637 | return NULL; |
638 | } | 638 | } |
639 | 639 | ||
640 | pr_reg->pr_aptpl_buf = kzalloc(su_dev->t10_pr.pr_aptpl_buf_len, | 640 | pr_reg->pr_aptpl_buf = kzalloc(su_dev->t10_pr.pr_aptpl_buf_len, |
641 | GFP_ATOMIC); | 641 | GFP_ATOMIC); |
642 | if (!pr_reg->pr_aptpl_buf) { | 642 | if (!pr_reg->pr_aptpl_buf) { |
643 | pr_err("Unable to allocate pr_reg->pr_aptpl_buf\n"); | 643 | pr_err("Unable to allocate pr_reg->pr_aptpl_buf\n"); |
644 | kmem_cache_free(t10_pr_reg_cache, pr_reg); | 644 | kmem_cache_free(t10_pr_reg_cache, pr_reg); |
645 | return NULL; | 645 | return NULL; |
646 | } | 646 | } |
647 | 647 | ||
648 | INIT_LIST_HEAD(&pr_reg->pr_reg_list); | 648 | INIT_LIST_HEAD(&pr_reg->pr_reg_list); |
649 | INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); | 649 | INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); |
650 | INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); | 650 | INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); |
651 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list); | 651 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list); |
652 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); | 652 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); |
653 | atomic_set(&pr_reg->pr_res_holders, 0); | 653 | atomic_set(&pr_reg->pr_res_holders, 0); |
654 | pr_reg->pr_reg_nacl = nacl; | 654 | pr_reg->pr_reg_nacl = nacl; |
655 | pr_reg->pr_reg_deve = deve; | 655 | pr_reg->pr_reg_deve = deve; |
656 | pr_reg->pr_res_mapped_lun = deve->mapped_lun; | 656 | pr_reg->pr_res_mapped_lun = deve->mapped_lun; |
657 | pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun; | 657 | pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun; |
658 | pr_reg->pr_res_key = sa_res_key; | 658 | pr_reg->pr_res_key = sa_res_key; |
659 | pr_reg->pr_reg_all_tg_pt = all_tg_pt; | 659 | pr_reg->pr_reg_all_tg_pt = all_tg_pt; |
660 | pr_reg->pr_reg_aptpl = aptpl; | 660 | pr_reg->pr_reg_aptpl = aptpl; |
661 | pr_reg->pr_reg_tg_pt_lun = deve->se_lun; | 661 | pr_reg->pr_reg_tg_pt_lun = deve->se_lun; |
662 | /* | 662 | /* |
663 | * If an ISID value for this SCSI Initiator Port exists, | 663 | * If an ISID value for this SCSI Initiator Port exists, |
664 | * save it to the registration now. | 664 | * save it to the registration now. |
665 | */ | 665 | */ |
666 | if (isid != NULL) { | 666 | if (isid != NULL) { |
667 | pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid); | 667 | pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid); |
668 | snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid); | 668 | snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid); |
669 | pr_reg->isid_present_at_reg = 1; | 669 | pr_reg->isid_present_at_reg = 1; |
670 | } | 670 | } |
671 | 671 | ||
672 | return pr_reg; | 672 | return pr_reg; |
673 | } | 673 | } |
674 | 674 | ||
675 | static int core_scsi3_lunacl_depend_item(struct se_dev_entry *); | 675 | static int core_scsi3_lunacl_depend_item(struct se_dev_entry *); |
676 | static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *); | 676 | static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *); |
677 | 677 | ||
678 | /* | 678 | /* |
679 | * Function used for handling PR registrations for ALL_TG_PT=1 and ALL_TG_PT=0 | 679 | * Function used for handling PR registrations for ALL_TG_PT=1 and ALL_TG_PT=0 |
680 | * modes. | 680 | * modes. |
681 | */ | 681 | */ |
682 | static struct t10_pr_registration *__core_scsi3_alloc_registration( | 682 | static struct t10_pr_registration *__core_scsi3_alloc_registration( |
683 | struct se_device *dev, | 683 | struct se_device *dev, |
684 | struct se_node_acl *nacl, | 684 | struct se_node_acl *nacl, |
685 | struct se_dev_entry *deve, | 685 | struct se_dev_entry *deve, |
686 | unsigned char *isid, | 686 | unsigned char *isid, |
687 | u64 sa_res_key, | 687 | u64 sa_res_key, |
688 | int all_tg_pt, | 688 | int all_tg_pt, |
689 | int aptpl) | 689 | int aptpl) |
690 | { | 690 | { |
691 | struct se_dev_entry *deve_tmp; | 691 | struct se_dev_entry *deve_tmp; |
692 | struct se_node_acl *nacl_tmp; | 692 | struct se_node_acl *nacl_tmp; |
693 | struct se_port *port, *port_tmp; | 693 | struct se_port *port, *port_tmp; |
694 | struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; | 694 | struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; |
695 | struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; | 695 | struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; |
696 | int ret; | 696 | int ret; |
697 | /* | 697 | /* |
698 | * Create a registration for the I_T Nexus upon which the | 698 | * Create a registration for the I_T Nexus upon which the |
699 | * PROUT REGISTER was received. | 699 | * PROUT REGISTER was received. |
700 | */ | 700 | */ |
701 | pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid, | 701 | pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid, |
702 | sa_res_key, all_tg_pt, aptpl); | 702 | sa_res_key, all_tg_pt, aptpl); |
703 | if (!pr_reg) | 703 | if (!pr_reg) |
704 | return NULL; | 704 | return NULL; |
705 | /* | 705 | /* |
706 | * Return pointer to pr_reg for ALL_TG_PT=0 | 706 | * Return pointer to pr_reg for ALL_TG_PT=0 |
707 | */ | 707 | */ |
708 | if (!all_tg_pt) | 708 | if (!all_tg_pt) |
709 | return pr_reg; | 709 | return pr_reg; |
710 | /* | 710 | /* |
711 | * Create list of matching SCSI Initiator Port registrations | 711 | * Create list of matching SCSI Initiator Port registrations |
712 | * for ALL_TG_PT=1 | 712 | * for ALL_TG_PT=1 |
713 | */ | 713 | */ |
714 | spin_lock(&dev->se_port_lock); | 714 | spin_lock(&dev->se_port_lock); |
715 | list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) { | 715 | list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) { |
716 | atomic_inc(&port->sep_tg_pt_ref_cnt); | 716 | atomic_inc(&port->sep_tg_pt_ref_cnt); |
717 | smp_mb__after_atomic_inc(); | 717 | smp_mb__after_atomic_inc(); |
718 | spin_unlock(&dev->se_port_lock); | 718 | spin_unlock(&dev->se_port_lock); |
719 | 719 | ||
720 | spin_lock_bh(&port->sep_alua_lock); | 720 | spin_lock_bh(&port->sep_alua_lock); |
721 | list_for_each_entry(deve_tmp, &port->sep_alua_list, | 721 | list_for_each_entry(deve_tmp, &port->sep_alua_list, |
722 | alua_port_list) { | 722 | alua_port_list) { |
723 | /* | 723 | /* |
724 | * This pointer will be NULL for demo mode MappedLUNs | 724 | * This pointer will be NULL for demo mode MappedLUNs |
725 | * that have not been make explict via a ConfigFS | 725 | * that have not been make explict via a ConfigFS |
726 | * MappedLUN group for the SCSI Initiator Node ACL. | 726 | * MappedLUN group for the SCSI Initiator Node ACL. |
727 | */ | 727 | */ |
728 | if (!deve_tmp->se_lun_acl) | 728 | if (!deve_tmp->se_lun_acl) |
729 | continue; | 729 | continue; |
730 | 730 | ||
731 | nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl; | 731 | nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl; |
732 | /* | 732 | /* |
733 | * Skip the matching struct se_node_acl that is allocated | 733 | * Skip the matching struct se_node_acl that is allocated |
734 | * above.. | 734 | * above.. |
735 | */ | 735 | */ |
736 | if (nacl == nacl_tmp) | 736 | if (nacl == nacl_tmp) |
737 | continue; | 737 | continue; |
738 | /* | 738 | /* |
739 | * Only perform PR registrations for target ports on | 739 | * Only perform PR registrations for target ports on |
740 | * the same fabric module as the REGISTER w/ ALL_TG_PT=1 | 740 | * the same fabric module as the REGISTER w/ ALL_TG_PT=1 |
741 | * arrived. | 741 | * arrived. |
742 | */ | 742 | */ |
743 | if (tfo != nacl_tmp->se_tpg->se_tpg_tfo) | 743 | if (tfo != nacl_tmp->se_tpg->se_tpg_tfo) |
744 | continue; | 744 | continue; |
745 | /* | 745 | /* |
746 | * Look for a matching Initiator Node ACL in ASCII format | 746 | * Look for a matching Initiator Node ACL in ASCII format |
747 | */ | 747 | */ |
748 | if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname)) | 748 | if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname)) |
749 | continue; | 749 | continue; |
750 | 750 | ||
751 | atomic_inc(&deve_tmp->pr_ref_count); | 751 | atomic_inc(&deve_tmp->pr_ref_count); |
752 | smp_mb__after_atomic_inc(); | 752 | smp_mb__after_atomic_inc(); |
753 | spin_unlock_bh(&port->sep_alua_lock); | 753 | spin_unlock_bh(&port->sep_alua_lock); |
754 | /* | 754 | /* |
755 | * Grab a configfs group dependency that is released | 755 | * Grab a configfs group dependency that is released |
756 | * for the exception path at label out: below, or upon | 756 | * for the exception path at label out: below, or upon |
757 | * completion of adding ALL_TG_PT=1 registrations in | 757 | * completion of adding ALL_TG_PT=1 registrations in |
758 | * __core_scsi3_add_registration() | 758 | * __core_scsi3_add_registration() |
759 | */ | 759 | */ |
760 | ret = core_scsi3_lunacl_depend_item(deve_tmp); | 760 | ret = core_scsi3_lunacl_depend_item(deve_tmp); |
761 | if (ret < 0) { | 761 | if (ret < 0) { |
762 | pr_err("core_scsi3_lunacl_depend" | 762 | pr_err("core_scsi3_lunacl_depend" |
763 | "_item() failed\n"); | 763 | "_item() failed\n"); |
764 | atomic_dec(&port->sep_tg_pt_ref_cnt); | 764 | atomic_dec(&port->sep_tg_pt_ref_cnt); |
765 | smp_mb__after_atomic_dec(); | 765 | smp_mb__after_atomic_dec(); |
766 | atomic_dec(&deve_tmp->pr_ref_count); | 766 | atomic_dec(&deve_tmp->pr_ref_count); |
767 | smp_mb__after_atomic_dec(); | 767 | smp_mb__after_atomic_dec(); |
768 | goto out; | 768 | goto out; |
769 | } | 769 | } |
770 | /* | 770 | /* |
771 | * Located a matching SCSI Initiator Port on a different | 771 | * Located a matching SCSI Initiator Port on a different |
772 | * port, allocate the pr_reg_atp and attach it to the | 772 | * port, allocate the pr_reg_atp and attach it to the |
773 | * pr_reg->pr_reg_atp_list that will be processed once | 773 | * pr_reg->pr_reg_atp_list that will be processed once |
774 | * the original *pr_reg is processed in | 774 | * the original *pr_reg is processed in |
775 | * __core_scsi3_add_registration() | 775 | * __core_scsi3_add_registration() |
776 | */ | 776 | */ |
777 | pr_reg_atp = __core_scsi3_do_alloc_registration(dev, | 777 | pr_reg_atp = __core_scsi3_do_alloc_registration(dev, |
778 | nacl_tmp, deve_tmp, NULL, | 778 | nacl_tmp, deve_tmp, NULL, |
779 | sa_res_key, all_tg_pt, aptpl); | 779 | sa_res_key, all_tg_pt, aptpl); |
780 | if (!pr_reg_atp) { | 780 | if (!pr_reg_atp) { |
781 | atomic_dec(&port->sep_tg_pt_ref_cnt); | 781 | atomic_dec(&port->sep_tg_pt_ref_cnt); |
782 | smp_mb__after_atomic_dec(); | 782 | smp_mb__after_atomic_dec(); |
783 | atomic_dec(&deve_tmp->pr_ref_count); | 783 | atomic_dec(&deve_tmp->pr_ref_count); |
784 | smp_mb__after_atomic_dec(); | 784 | smp_mb__after_atomic_dec(); |
785 | core_scsi3_lunacl_undepend_item(deve_tmp); | 785 | core_scsi3_lunacl_undepend_item(deve_tmp); |
786 | goto out; | 786 | goto out; |
787 | } | 787 | } |
788 | 788 | ||
789 | list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list, | 789 | list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list, |
790 | &pr_reg->pr_reg_atp_list); | 790 | &pr_reg->pr_reg_atp_list); |
791 | spin_lock_bh(&port->sep_alua_lock); | 791 | spin_lock_bh(&port->sep_alua_lock); |
792 | } | 792 | } |
793 | spin_unlock_bh(&port->sep_alua_lock); | 793 | spin_unlock_bh(&port->sep_alua_lock); |
794 | 794 | ||
795 | spin_lock(&dev->se_port_lock); | 795 | spin_lock(&dev->se_port_lock); |
796 | atomic_dec(&port->sep_tg_pt_ref_cnt); | 796 | atomic_dec(&port->sep_tg_pt_ref_cnt); |
797 | smp_mb__after_atomic_dec(); | 797 | smp_mb__after_atomic_dec(); |
798 | } | 798 | } |
799 | spin_unlock(&dev->se_port_lock); | 799 | spin_unlock(&dev->se_port_lock); |
800 | 800 | ||
801 | return pr_reg; | 801 | return pr_reg; |
802 | out: | 802 | out: |
803 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, | 803 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, |
804 | &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { | 804 | &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { |
805 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); | 805 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); |
806 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); | 806 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); |
807 | kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp); | 807 | kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp); |
808 | } | 808 | } |
809 | kmem_cache_free(t10_pr_reg_cache, pr_reg); | 809 | kmem_cache_free(t10_pr_reg_cache, pr_reg); |
810 | return NULL; | 810 | return NULL; |
811 | } | 811 | } |
812 | 812 | ||
813 | int core_scsi3_alloc_aptpl_registration( | 813 | int core_scsi3_alloc_aptpl_registration( |
814 | struct t10_reservation *pr_tmpl, | 814 | struct t10_reservation *pr_tmpl, |
815 | u64 sa_res_key, | 815 | u64 sa_res_key, |
816 | unsigned char *i_port, | 816 | unsigned char *i_port, |
817 | unsigned char *isid, | 817 | unsigned char *isid, |
818 | u32 mapped_lun, | 818 | u32 mapped_lun, |
819 | unsigned char *t_port, | 819 | unsigned char *t_port, |
820 | u16 tpgt, | 820 | u16 tpgt, |
821 | u32 target_lun, | 821 | u32 target_lun, |
822 | int res_holder, | 822 | int res_holder, |
823 | int all_tg_pt, | 823 | int all_tg_pt, |
824 | u8 type) | 824 | u8 type) |
825 | { | 825 | { |
826 | struct t10_pr_registration *pr_reg; | 826 | struct t10_pr_registration *pr_reg; |
827 | 827 | ||
828 | if (!i_port || !t_port || !sa_res_key) { | 828 | if (!i_port || !t_port || !sa_res_key) { |
829 | pr_err("Illegal parameters for APTPL registration\n"); | 829 | pr_err("Illegal parameters for APTPL registration\n"); |
830 | return -EINVAL; | 830 | return -EINVAL; |
831 | } | 831 | } |
832 | 832 | ||
833 | pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_KERNEL); | 833 | pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_KERNEL); |
834 | if (!pr_reg) { | 834 | if (!pr_reg) { |
835 | pr_err("Unable to allocate struct t10_pr_registration\n"); | 835 | pr_err("Unable to allocate struct t10_pr_registration\n"); |
836 | return -ENOMEM; | 836 | return -ENOMEM; |
837 | } | 837 | } |
838 | pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL); | 838 | pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL); |
839 | 839 | ||
840 | INIT_LIST_HEAD(&pr_reg->pr_reg_list); | 840 | INIT_LIST_HEAD(&pr_reg->pr_reg_list); |
841 | INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); | 841 | INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); |
842 | INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); | 842 | INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); |
843 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list); | 843 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list); |
844 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); | 844 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); |
845 | atomic_set(&pr_reg->pr_res_holders, 0); | 845 | atomic_set(&pr_reg->pr_res_holders, 0); |
846 | pr_reg->pr_reg_nacl = NULL; | 846 | pr_reg->pr_reg_nacl = NULL; |
847 | pr_reg->pr_reg_deve = NULL; | 847 | pr_reg->pr_reg_deve = NULL; |
848 | pr_reg->pr_res_mapped_lun = mapped_lun; | 848 | pr_reg->pr_res_mapped_lun = mapped_lun; |
849 | pr_reg->pr_aptpl_target_lun = target_lun; | 849 | pr_reg->pr_aptpl_target_lun = target_lun; |
850 | pr_reg->pr_res_key = sa_res_key; | 850 | pr_reg->pr_res_key = sa_res_key; |
851 | pr_reg->pr_reg_all_tg_pt = all_tg_pt; | 851 | pr_reg->pr_reg_all_tg_pt = all_tg_pt; |
852 | pr_reg->pr_reg_aptpl = 1; | 852 | pr_reg->pr_reg_aptpl = 1; |
853 | pr_reg->pr_reg_tg_pt_lun = NULL; | 853 | pr_reg->pr_reg_tg_pt_lun = NULL; |
854 | pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */ | 854 | pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */ |
855 | pr_reg->pr_res_type = type; | 855 | pr_reg->pr_res_type = type; |
856 | /* | 856 | /* |
857 | * If an ISID value had been saved in APTPL metadata for this | 857 | * If an ISID value had been saved in APTPL metadata for this |
858 | * SCSI Initiator Port, restore it now. | 858 | * SCSI Initiator Port, restore it now. |
859 | */ | 859 | */ |
860 | if (isid != NULL) { | 860 | if (isid != NULL) { |
861 | pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid); | 861 | pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid); |
862 | snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid); | 862 | snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid); |
863 | pr_reg->isid_present_at_reg = 1; | 863 | pr_reg->isid_present_at_reg = 1; |
864 | } | 864 | } |
865 | /* | 865 | /* |
866 | * Copy the i_port and t_port information from caller. | 866 | * Copy the i_port and t_port information from caller. |
867 | */ | 867 | */ |
868 | snprintf(pr_reg->pr_iport, PR_APTPL_MAX_IPORT_LEN, "%s", i_port); | 868 | snprintf(pr_reg->pr_iport, PR_APTPL_MAX_IPORT_LEN, "%s", i_port); |
869 | snprintf(pr_reg->pr_tport, PR_APTPL_MAX_TPORT_LEN, "%s", t_port); | 869 | snprintf(pr_reg->pr_tport, PR_APTPL_MAX_TPORT_LEN, "%s", t_port); |
870 | pr_reg->pr_reg_tpgt = tpgt; | 870 | pr_reg->pr_reg_tpgt = tpgt; |
871 | /* | 871 | /* |
872 | * Set pr_res_holder from caller, the pr_reg who is the reservation | 872 | * Set pr_res_holder from caller, the pr_reg who is the reservation |
873 | * holder will get it's pointer set in core_scsi3_aptpl_reserve() once | 873 | * holder will get it's pointer set in core_scsi3_aptpl_reserve() once |
874 | * the Initiator Node LUN ACL from the fabric module is created for | 874 | * the Initiator Node LUN ACL from the fabric module is created for |
875 | * this registration. | 875 | * this registration. |
876 | */ | 876 | */ |
877 | pr_reg->pr_res_holder = res_holder; | 877 | pr_reg->pr_res_holder = res_holder; |
878 | 878 | ||
879 | list_add_tail(&pr_reg->pr_reg_aptpl_list, &pr_tmpl->aptpl_reg_list); | 879 | list_add_tail(&pr_reg->pr_reg_aptpl_list, &pr_tmpl->aptpl_reg_list); |
880 | pr_debug("SPC-3 PR APTPL Successfully added registration%s from" | 880 | pr_debug("SPC-3 PR APTPL Successfully added registration%s from" |
881 | " metadata\n", (res_holder) ? "+reservation" : ""); | 881 | " metadata\n", (res_holder) ? "+reservation" : ""); |
882 | return 0; | 882 | return 0; |
883 | } | 883 | } |
884 | 884 | ||
885 | static void core_scsi3_aptpl_reserve( | 885 | static void core_scsi3_aptpl_reserve( |
886 | struct se_device *dev, | 886 | struct se_device *dev, |
887 | struct se_portal_group *tpg, | 887 | struct se_portal_group *tpg, |
888 | struct se_node_acl *node_acl, | 888 | struct se_node_acl *node_acl, |
889 | struct t10_pr_registration *pr_reg) | 889 | struct t10_pr_registration *pr_reg) |
890 | { | 890 | { |
891 | char i_buf[PR_REG_ISID_ID_LEN]; | 891 | char i_buf[PR_REG_ISID_ID_LEN]; |
892 | int prf_isid; | 892 | int prf_isid; |
893 | 893 | ||
894 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 894 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
895 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 895 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
896 | PR_REG_ISID_ID_LEN); | 896 | PR_REG_ISID_ID_LEN); |
897 | 897 | ||
898 | spin_lock(&dev->dev_reservation_lock); | 898 | spin_lock(&dev->dev_reservation_lock); |
899 | dev->dev_pr_res_holder = pr_reg; | 899 | dev->dev_pr_res_holder = pr_reg; |
900 | spin_unlock(&dev->dev_reservation_lock); | 900 | spin_unlock(&dev->dev_reservation_lock); |
901 | 901 | ||
902 | pr_debug("SPC-3 PR [%s] Service Action: APTPL RESERVE created" | 902 | pr_debug("SPC-3 PR [%s] Service Action: APTPL RESERVE created" |
903 | " new reservation holder TYPE: %s ALL_TG_PT: %d\n", | 903 | " new reservation holder TYPE: %s ALL_TG_PT: %d\n", |
904 | tpg->se_tpg_tfo->get_fabric_name(), | 904 | tpg->se_tpg_tfo->get_fabric_name(), |
905 | core_scsi3_pr_dump_type(pr_reg->pr_res_type), | 905 | core_scsi3_pr_dump_type(pr_reg->pr_res_type), |
906 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); | 906 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); |
907 | pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n", | 907 | pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n", |
908 | tpg->se_tpg_tfo->get_fabric_name(), node_acl->initiatorname, | 908 | tpg->se_tpg_tfo->get_fabric_name(), node_acl->initiatorname, |
909 | (prf_isid) ? &i_buf[0] : ""); | 909 | (prf_isid) ? &i_buf[0] : ""); |
910 | } | 910 | } |
911 | 911 | ||
912 | static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *, | 912 | static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *, |
913 | struct t10_pr_registration *, int, int); | 913 | struct t10_pr_registration *, int, int); |
914 | 914 | ||
915 | static int __core_scsi3_check_aptpl_registration( | 915 | static int __core_scsi3_check_aptpl_registration( |
916 | struct se_device *dev, | 916 | struct se_device *dev, |
917 | struct se_portal_group *tpg, | 917 | struct se_portal_group *tpg, |
918 | struct se_lun *lun, | 918 | struct se_lun *lun, |
919 | u32 target_lun, | 919 | u32 target_lun, |
920 | struct se_node_acl *nacl, | 920 | struct se_node_acl *nacl, |
921 | struct se_dev_entry *deve) | 921 | struct se_dev_entry *deve) |
922 | { | 922 | { |
923 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; | 923 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; |
924 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 924 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
925 | unsigned char i_port[PR_APTPL_MAX_IPORT_LEN]; | 925 | unsigned char i_port[PR_APTPL_MAX_IPORT_LEN]; |
926 | unsigned char t_port[PR_APTPL_MAX_TPORT_LEN]; | 926 | unsigned char t_port[PR_APTPL_MAX_TPORT_LEN]; |
927 | u16 tpgt; | 927 | u16 tpgt; |
928 | 928 | ||
929 | memset(i_port, 0, PR_APTPL_MAX_IPORT_LEN); | 929 | memset(i_port, 0, PR_APTPL_MAX_IPORT_LEN); |
930 | memset(t_port, 0, PR_APTPL_MAX_TPORT_LEN); | 930 | memset(t_port, 0, PR_APTPL_MAX_TPORT_LEN); |
931 | /* | 931 | /* |
932 | * Copy Initiator Port information from struct se_node_acl | 932 | * Copy Initiator Port information from struct se_node_acl |
933 | */ | 933 | */ |
934 | snprintf(i_port, PR_APTPL_MAX_IPORT_LEN, "%s", nacl->initiatorname); | 934 | snprintf(i_port, PR_APTPL_MAX_IPORT_LEN, "%s", nacl->initiatorname); |
935 | snprintf(t_port, PR_APTPL_MAX_TPORT_LEN, "%s", | 935 | snprintf(t_port, PR_APTPL_MAX_TPORT_LEN, "%s", |
936 | tpg->se_tpg_tfo->tpg_get_wwn(tpg)); | 936 | tpg->se_tpg_tfo->tpg_get_wwn(tpg)); |
937 | tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg); | 937 | tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg); |
938 | /* | 938 | /* |
939 | * Look for the matching registrations+reservation from those | 939 | * Look for the matching registrations+reservation from those |
940 | * created from APTPL metadata. Note that multiple registrations | 940 | * created from APTPL metadata. Note that multiple registrations |
941 | * may exist for fabrics that use ISIDs in their SCSI Initiator Port | 941 | * may exist for fabrics that use ISIDs in their SCSI Initiator Port |
942 | * TransportIDs. | 942 | * TransportIDs. |
943 | */ | 943 | */ |
944 | spin_lock(&pr_tmpl->aptpl_reg_lock); | 944 | spin_lock(&pr_tmpl->aptpl_reg_lock); |
945 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list, | 945 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list, |
946 | pr_reg_aptpl_list) { | 946 | pr_reg_aptpl_list) { |
947 | if (!strcmp(pr_reg->pr_iport, i_port) && | 947 | if (!strcmp(pr_reg->pr_iport, i_port) && |
948 | (pr_reg->pr_res_mapped_lun == deve->mapped_lun) && | 948 | (pr_reg->pr_res_mapped_lun == deve->mapped_lun) && |
949 | !(strcmp(pr_reg->pr_tport, t_port)) && | 949 | !(strcmp(pr_reg->pr_tport, t_port)) && |
950 | (pr_reg->pr_reg_tpgt == tpgt) && | 950 | (pr_reg->pr_reg_tpgt == tpgt) && |
951 | (pr_reg->pr_aptpl_target_lun == target_lun)) { | 951 | (pr_reg->pr_aptpl_target_lun == target_lun)) { |
952 | 952 | ||
953 | pr_reg->pr_reg_nacl = nacl; | 953 | pr_reg->pr_reg_nacl = nacl; |
954 | pr_reg->pr_reg_deve = deve; | 954 | pr_reg->pr_reg_deve = deve; |
955 | pr_reg->pr_reg_tg_pt_lun = lun; | 955 | pr_reg->pr_reg_tg_pt_lun = lun; |
956 | 956 | ||
957 | list_del(&pr_reg->pr_reg_aptpl_list); | 957 | list_del(&pr_reg->pr_reg_aptpl_list); |
958 | spin_unlock(&pr_tmpl->aptpl_reg_lock); | 958 | spin_unlock(&pr_tmpl->aptpl_reg_lock); |
959 | /* | 959 | /* |
960 | * At this point all of the pointers in *pr_reg will | 960 | * At this point all of the pointers in *pr_reg will |
961 | * be setup, so go ahead and add the registration. | 961 | * be setup, so go ahead and add the registration. |
962 | */ | 962 | */ |
963 | 963 | ||
964 | __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0); | 964 | __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0); |
965 | /* | 965 | /* |
966 | * If this registration is the reservation holder, | 966 | * If this registration is the reservation holder, |
967 | * make that happen now.. | 967 | * make that happen now.. |
968 | */ | 968 | */ |
969 | if (pr_reg->pr_res_holder) | 969 | if (pr_reg->pr_res_holder) |
970 | core_scsi3_aptpl_reserve(dev, tpg, | 970 | core_scsi3_aptpl_reserve(dev, tpg, |
971 | nacl, pr_reg); | 971 | nacl, pr_reg); |
972 | /* | 972 | /* |
973 | * Reenable pr_aptpl_active to accept new metadata | 973 | * Reenable pr_aptpl_active to accept new metadata |
974 | * updates once the SCSI device is active again.. | 974 | * updates once the SCSI device is active again.. |
975 | */ | 975 | */ |
976 | spin_lock(&pr_tmpl->aptpl_reg_lock); | 976 | spin_lock(&pr_tmpl->aptpl_reg_lock); |
977 | pr_tmpl->pr_aptpl_active = 1; | 977 | pr_tmpl->pr_aptpl_active = 1; |
978 | } | 978 | } |
979 | } | 979 | } |
980 | spin_unlock(&pr_tmpl->aptpl_reg_lock); | 980 | spin_unlock(&pr_tmpl->aptpl_reg_lock); |
981 | 981 | ||
982 | return 0; | 982 | return 0; |
983 | } | 983 | } |
984 | 984 | ||
985 | int core_scsi3_check_aptpl_registration( | 985 | int core_scsi3_check_aptpl_registration( |
986 | struct se_device *dev, | 986 | struct se_device *dev, |
987 | struct se_portal_group *tpg, | 987 | struct se_portal_group *tpg, |
988 | struct se_lun *lun, | 988 | struct se_lun *lun, |
989 | struct se_lun_acl *lun_acl) | 989 | struct se_lun_acl *lun_acl) |
990 | { | 990 | { |
991 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; | 991 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; |
992 | struct se_node_acl *nacl = lun_acl->se_lun_nacl; | 992 | struct se_node_acl *nacl = lun_acl->se_lun_nacl; |
993 | struct se_dev_entry *deve = &nacl->device_list[lun_acl->mapped_lun]; | 993 | struct se_dev_entry *deve = &nacl->device_list[lun_acl->mapped_lun]; |
994 | 994 | ||
995 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) | 995 | if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) |
996 | return 0; | 996 | return 0; |
997 | 997 | ||
998 | return __core_scsi3_check_aptpl_registration(dev, tpg, lun, | 998 | return __core_scsi3_check_aptpl_registration(dev, tpg, lun, |
999 | lun->unpacked_lun, nacl, deve); | 999 | lun->unpacked_lun, nacl, deve); |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | static void __core_scsi3_dump_registration( | 1002 | static void __core_scsi3_dump_registration( |
1003 | struct target_core_fabric_ops *tfo, | 1003 | struct target_core_fabric_ops *tfo, |
1004 | struct se_device *dev, | 1004 | struct se_device *dev, |
1005 | struct se_node_acl *nacl, | 1005 | struct se_node_acl *nacl, |
1006 | struct t10_pr_registration *pr_reg, | 1006 | struct t10_pr_registration *pr_reg, |
1007 | int register_type) | 1007 | int register_type) |
1008 | { | 1008 | { |
1009 | struct se_portal_group *se_tpg = nacl->se_tpg; | 1009 | struct se_portal_group *se_tpg = nacl->se_tpg; |
1010 | char i_buf[PR_REG_ISID_ID_LEN]; | 1010 | char i_buf[PR_REG_ISID_ID_LEN]; |
1011 | int prf_isid; | 1011 | int prf_isid; |
1012 | 1012 | ||
1013 | memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN); | 1013 | memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN); |
1014 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 1014 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
1015 | PR_REG_ISID_ID_LEN); | 1015 | PR_REG_ISID_ID_LEN); |
1016 | 1016 | ||
1017 | pr_debug("SPC-3 PR [%s] Service Action: REGISTER%s Initiator" | 1017 | pr_debug("SPC-3 PR [%s] Service Action: REGISTER%s Initiator" |
1018 | " Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ? | 1018 | " Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ? |
1019 | "_AND_MOVE" : (register_type == 1) ? | 1019 | "_AND_MOVE" : (register_type == 1) ? |
1020 | "_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname, | 1020 | "_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname, |
1021 | (prf_isid) ? i_buf : ""); | 1021 | (prf_isid) ? i_buf : ""); |
1022 | pr_debug("SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n", | 1022 | pr_debug("SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n", |
1023 | tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg), | 1023 | tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg), |
1024 | tfo->tpg_get_tag(se_tpg)); | 1024 | tfo->tpg_get_tag(se_tpg)); |
1025 | pr_debug("SPC-3 PR [%s] for %s TCM Subsystem %s Object Target" | 1025 | pr_debug("SPC-3 PR [%s] for %s TCM Subsystem %s Object Target" |
1026 | " Port(s)\n", tfo->get_fabric_name(), | 1026 | " Port(s)\n", tfo->get_fabric_name(), |
1027 | (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", | 1027 | (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", |
1028 | dev->transport->name); | 1028 | dev->transport->name); |
1029 | pr_debug("SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:" | 1029 | pr_debug("SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:" |
1030 | " 0x%08x APTPL: %d\n", tfo->get_fabric_name(), | 1030 | " 0x%08x APTPL: %d\n", tfo->get_fabric_name(), |
1031 | pr_reg->pr_res_key, pr_reg->pr_res_generation, | 1031 | pr_reg->pr_res_key, pr_reg->pr_res_generation, |
1032 | pr_reg->pr_reg_aptpl); | 1032 | pr_reg->pr_reg_aptpl); |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | /* | 1035 | /* |
1036 | * this function can be called with struct se_device->dev_reservation_lock | 1036 | * this function can be called with struct se_device->dev_reservation_lock |
1037 | * when register_move = 1 | 1037 | * when register_move = 1 |
1038 | */ | 1038 | */ |
1039 | static void __core_scsi3_add_registration( | 1039 | static void __core_scsi3_add_registration( |
1040 | struct se_device *dev, | 1040 | struct se_device *dev, |
1041 | struct se_node_acl *nacl, | 1041 | struct se_node_acl *nacl, |
1042 | struct t10_pr_registration *pr_reg, | 1042 | struct t10_pr_registration *pr_reg, |
1043 | int register_type, | 1043 | int register_type, |
1044 | int register_move) | 1044 | int register_move) |
1045 | { | 1045 | { |
1046 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; | 1046 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; |
1047 | struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; | 1047 | struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; |
1048 | struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; | 1048 | struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; |
1049 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 1049 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
1050 | 1050 | ||
1051 | /* | 1051 | /* |
1052 | * Increment PRgeneration counter for struct se_device upon a successful | 1052 | * Increment PRgeneration counter for struct se_device upon a successful |
1053 | * REGISTER, see spc4r17 section 6.3.2 READ_KEYS service action | 1053 | * REGISTER, see spc4r17 section 6.3.2 READ_KEYS service action |
1054 | * | 1054 | * |
1055 | * Also, when register_move = 1 for PROUT REGISTER_AND_MOVE service | 1055 | * Also, when register_move = 1 for PROUT REGISTER_AND_MOVE service |
1056 | * action, the struct se_device->dev_reservation_lock will already be held, | 1056 | * action, the struct se_device->dev_reservation_lock will already be held, |
1057 | * so we do not call core_scsi3_pr_generation() which grabs the lock | 1057 | * so we do not call core_scsi3_pr_generation() which grabs the lock |
1058 | * for the REGISTER. | 1058 | * for the REGISTER. |
1059 | */ | 1059 | */ |
1060 | pr_reg->pr_res_generation = (register_move) ? | 1060 | pr_reg->pr_res_generation = (register_move) ? |
1061 | su_dev->t10_pr.pr_generation++ : | 1061 | su_dev->t10_pr.pr_generation++ : |
1062 | core_scsi3_pr_generation(dev); | 1062 | core_scsi3_pr_generation(dev); |
1063 | 1063 | ||
1064 | spin_lock(&pr_tmpl->registration_lock); | 1064 | spin_lock(&pr_tmpl->registration_lock); |
1065 | list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); | 1065 | list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); |
1066 | pr_reg->pr_reg_deve->def_pr_registered = 1; | 1066 | pr_reg->pr_reg_deve->def_pr_registered = 1; |
1067 | 1067 | ||
1068 | __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); | 1068 | __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); |
1069 | spin_unlock(&pr_tmpl->registration_lock); | 1069 | spin_unlock(&pr_tmpl->registration_lock); |
1070 | /* | 1070 | /* |
1071 | * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. | 1071 | * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. |
1072 | */ | 1072 | */ |
1073 | if (!pr_reg->pr_reg_all_tg_pt || register_move) | 1073 | if (!pr_reg->pr_reg_all_tg_pt || register_move) |
1074 | return; | 1074 | return; |
1075 | /* | 1075 | /* |
1076 | * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1 | 1076 | * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1 |
1077 | * allocated in __core_scsi3_alloc_registration() | 1077 | * allocated in __core_scsi3_alloc_registration() |
1078 | */ | 1078 | */ |
1079 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, | 1079 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, |
1080 | &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { | 1080 | &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { |
1081 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); | 1081 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); |
1082 | 1082 | ||
1083 | pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); | 1083 | pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); |
1084 | 1084 | ||
1085 | spin_lock(&pr_tmpl->registration_lock); | 1085 | spin_lock(&pr_tmpl->registration_lock); |
1086 | list_add_tail(&pr_reg_tmp->pr_reg_list, | 1086 | list_add_tail(&pr_reg_tmp->pr_reg_list, |
1087 | &pr_tmpl->registration_list); | 1087 | &pr_tmpl->registration_list); |
1088 | pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; | 1088 | pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; |
1089 | 1089 | ||
1090 | __core_scsi3_dump_registration(tfo, dev, | 1090 | __core_scsi3_dump_registration(tfo, dev, |
1091 | pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, | 1091 | pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, |
1092 | register_type); | 1092 | register_type); |
1093 | spin_unlock(&pr_tmpl->registration_lock); | 1093 | spin_unlock(&pr_tmpl->registration_lock); |
1094 | /* | 1094 | /* |
1095 | * Drop configfs group dependency reference from | 1095 | * Drop configfs group dependency reference from |
1096 | * __core_scsi3_alloc_registration() | 1096 | * __core_scsi3_alloc_registration() |
1097 | */ | 1097 | */ |
1098 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); | 1098 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); |
1099 | } | 1099 | } |
1100 | } | 1100 | } |
1101 | 1101 | ||
1102 | static int core_scsi3_alloc_registration( | 1102 | static int core_scsi3_alloc_registration( |
1103 | struct se_device *dev, | 1103 | struct se_device *dev, |
1104 | struct se_node_acl *nacl, | 1104 | struct se_node_acl *nacl, |
1105 | struct se_dev_entry *deve, | 1105 | struct se_dev_entry *deve, |
1106 | unsigned char *isid, | 1106 | unsigned char *isid, |
1107 | u64 sa_res_key, | 1107 | u64 sa_res_key, |
1108 | int all_tg_pt, | 1108 | int all_tg_pt, |
1109 | int aptpl, | 1109 | int aptpl, |
1110 | int register_type, | 1110 | int register_type, |
1111 | int register_move) | 1111 | int register_move) |
1112 | { | 1112 | { |
1113 | struct t10_pr_registration *pr_reg; | 1113 | struct t10_pr_registration *pr_reg; |
1114 | 1114 | ||
1115 | pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid, | 1115 | pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid, |
1116 | sa_res_key, all_tg_pt, aptpl); | 1116 | sa_res_key, all_tg_pt, aptpl); |
1117 | if (!pr_reg) | 1117 | if (!pr_reg) |
1118 | return -EPERM; | 1118 | return -EPERM; |
1119 | 1119 | ||
1120 | __core_scsi3_add_registration(dev, nacl, pr_reg, | 1120 | __core_scsi3_add_registration(dev, nacl, pr_reg, |
1121 | register_type, register_move); | 1121 | register_type, register_move); |
1122 | return 0; | 1122 | return 0; |
1123 | } | 1123 | } |
1124 | 1124 | ||
1125 | static struct t10_pr_registration *__core_scsi3_locate_pr_reg( | 1125 | static struct t10_pr_registration *__core_scsi3_locate_pr_reg( |
1126 | struct se_device *dev, | 1126 | struct se_device *dev, |
1127 | struct se_node_acl *nacl, | 1127 | struct se_node_acl *nacl, |
1128 | unsigned char *isid) | 1128 | unsigned char *isid) |
1129 | { | 1129 | { |
1130 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 1130 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
1131 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; | 1131 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; |
1132 | struct se_portal_group *tpg; | 1132 | struct se_portal_group *tpg; |
1133 | 1133 | ||
1134 | spin_lock(&pr_tmpl->registration_lock); | 1134 | spin_lock(&pr_tmpl->registration_lock); |
1135 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 1135 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
1136 | &pr_tmpl->registration_list, pr_reg_list) { | 1136 | &pr_tmpl->registration_list, pr_reg_list) { |
1137 | /* | 1137 | /* |
1138 | * First look for a matching struct se_node_acl | 1138 | * First look for a matching struct se_node_acl |
1139 | */ | 1139 | */ |
1140 | if (pr_reg->pr_reg_nacl != nacl) | 1140 | if (pr_reg->pr_reg_nacl != nacl) |
1141 | continue; | 1141 | continue; |
1142 | 1142 | ||
1143 | tpg = pr_reg->pr_reg_nacl->se_tpg; | 1143 | tpg = pr_reg->pr_reg_nacl->se_tpg; |
1144 | /* | 1144 | /* |
1145 | * If this registration does NOT contain a fabric provided | 1145 | * If this registration does NOT contain a fabric provided |
1146 | * ISID, then we have found a match. | 1146 | * ISID, then we have found a match. |
1147 | */ | 1147 | */ |
1148 | if (!pr_reg->isid_present_at_reg) { | 1148 | if (!pr_reg->isid_present_at_reg) { |
1149 | /* | 1149 | /* |
1150 | * Determine if this SCSI device server requires that | 1150 | * Determine if this SCSI device server requires that |
1151 | * SCSI Intiatior TransportID w/ ISIDs is enforced | 1151 | * SCSI Intiatior TransportID w/ ISIDs is enforced |
1152 | * for fabric modules (iSCSI) requiring them. | 1152 | * for fabric modules (iSCSI) requiring them. |
1153 | */ | 1153 | */ |
1154 | if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) { | 1154 | if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) { |
1155 | if (dev->se_sub_dev->se_dev_attrib.enforce_pr_isids) | 1155 | if (dev->se_sub_dev->se_dev_attrib.enforce_pr_isids) |
1156 | continue; | 1156 | continue; |
1157 | } | 1157 | } |
1158 | atomic_inc(&pr_reg->pr_res_holders); | 1158 | atomic_inc(&pr_reg->pr_res_holders); |
1159 | smp_mb__after_atomic_inc(); | 1159 | smp_mb__after_atomic_inc(); |
1160 | spin_unlock(&pr_tmpl->registration_lock); | 1160 | spin_unlock(&pr_tmpl->registration_lock); |
1161 | return pr_reg; | 1161 | return pr_reg; |
1162 | } | 1162 | } |
1163 | /* | 1163 | /* |
1164 | * If the *pr_reg contains a fabric defined ISID for multi-value | 1164 | * If the *pr_reg contains a fabric defined ISID for multi-value |
1165 | * SCSI Initiator Port TransportIDs, then we expect a valid | 1165 | * SCSI Initiator Port TransportIDs, then we expect a valid |
1166 | * matching ISID to be provided by the local SCSI Initiator Port. | 1166 | * matching ISID to be provided by the local SCSI Initiator Port. |
1167 | */ | 1167 | */ |
1168 | if (!isid) | 1168 | if (!isid) |
1169 | continue; | 1169 | continue; |
1170 | if (strcmp(isid, pr_reg->pr_reg_isid)) | 1170 | if (strcmp(isid, pr_reg->pr_reg_isid)) |
1171 | continue; | 1171 | continue; |
1172 | 1172 | ||
1173 | atomic_inc(&pr_reg->pr_res_holders); | 1173 | atomic_inc(&pr_reg->pr_res_holders); |
1174 | smp_mb__after_atomic_inc(); | 1174 | smp_mb__after_atomic_inc(); |
1175 | spin_unlock(&pr_tmpl->registration_lock); | 1175 | spin_unlock(&pr_tmpl->registration_lock); |
1176 | return pr_reg; | 1176 | return pr_reg; |
1177 | } | 1177 | } |
1178 | spin_unlock(&pr_tmpl->registration_lock); | 1178 | spin_unlock(&pr_tmpl->registration_lock); |
1179 | 1179 | ||
1180 | return NULL; | 1180 | return NULL; |
1181 | } | 1181 | } |
1182 | 1182 | ||
1183 | static struct t10_pr_registration *core_scsi3_locate_pr_reg( | 1183 | static struct t10_pr_registration *core_scsi3_locate_pr_reg( |
1184 | struct se_device *dev, | 1184 | struct se_device *dev, |
1185 | struct se_node_acl *nacl, | 1185 | struct se_node_acl *nacl, |
1186 | struct se_session *sess) | 1186 | struct se_session *sess) |
1187 | { | 1187 | { |
1188 | struct se_portal_group *tpg = nacl->se_tpg; | 1188 | struct se_portal_group *tpg = nacl->se_tpg; |
1189 | unsigned char buf[PR_REG_ISID_LEN], *isid_ptr = NULL; | 1189 | unsigned char buf[PR_REG_ISID_LEN], *isid_ptr = NULL; |
1190 | 1190 | ||
1191 | if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) { | 1191 | if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) { |
1192 | memset(&buf[0], 0, PR_REG_ISID_LEN); | 1192 | memset(&buf[0], 0, PR_REG_ISID_LEN); |
1193 | tpg->se_tpg_tfo->sess_get_initiator_sid(sess, &buf[0], | 1193 | tpg->se_tpg_tfo->sess_get_initiator_sid(sess, &buf[0], |
1194 | PR_REG_ISID_LEN); | 1194 | PR_REG_ISID_LEN); |
1195 | isid_ptr = &buf[0]; | 1195 | isid_ptr = &buf[0]; |
1196 | } | 1196 | } |
1197 | 1197 | ||
1198 | return __core_scsi3_locate_pr_reg(dev, nacl, isid_ptr); | 1198 | return __core_scsi3_locate_pr_reg(dev, nacl, isid_ptr); |
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg) | 1201 | static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg) |
1202 | { | 1202 | { |
1203 | atomic_dec(&pr_reg->pr_res_holders); | 1203 | atomic_dec(&pr_reg->pr_res_holders); |
1204 | smp_mb__after_atomic_dec(); | 1204 | smp_mb__after_atomic_dec(); |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | static int core_scsi3_check_implict_release( | 1207 | static int core_scsi3_check_implict_release( |
1208 | struct se_device *dev, | 1208 | struct se_device *dev, |
1209 | struct t10_pr_registration *pr_reg) | 1209 | struct t10_pr_registration *pr_reg) |
1210 | { | 1210 | { |
1211 | struct se_node_acl *nacl = pr_reg->pr_reg_nacl; | 1211 | struct se_node_acl *nacl = pr_reg->pr_reg_nacl; |
1212 | struct t10_pr_registration *pr_res_holder; | 1212 | struct t10_pr_registration *pr_res_holder; |
1213 | int ret = 0; | 1213 | int ret = 0; |
1214 | 1214 | ||
1215 | spin_lock(&dev->dev_reservation_lock); | 1215 | spin_lock(&dev->dev_reservation_lock); |
1216 | pr_res_holder = dev->dev_pr_res_holder; | 1216 | pr_res_holder = dev->dev_pr_res_holder; |
1217 | if (!pr_res_holder) { | 1217 | if (!pr_res_holder) { |
1218 | spin_unlock(&dev->dev_reservation_lock); | 1218 | spin_unlock(&dev->dev_reservation_lock); |
1219 | return ret; | 1219 | return ret; |
1220 | } | 1220 | } |
1221 | if (pr_res_holder == pr_reg) { | 1221 | if (pr_res_holder == pr_reg) { |
1222 | /* | 1222 | /* |
1223 | * Perform an implict RELEASE if the registration that | 1223 | * Perform an implict RELEASE if the registration that |
1224 | * is being released is holding the reservation. | 1224 | * is being released is holding the reservation. |
1225 | * | 1225 | * |
1226 | * From spc4r17, section 5.7.11.1: | 1226 | * From spc4r17, section 5.7.11.1: |
1227 | * | 1227 | * |
1228 | * e) If the I_T nexus is the persistent reservation holder | 1228 | * e) If the I_T nexus is the persistent reservation holder |
1229 | * and the persistent reservation is not an all registrants | 1229 | * and the persistent reservation is not an all registrants |
1230 | * type, then a PERSISTENT RESERVE OUT command with REGISTER | 1230 | * type, then a PERSISTENT RESERVE OUT command with REGISTER |
1231 | * service action or REGISTER AND IGNORE EXISTING KEY | 1231 | * service action or REGISTER AND IGNORE EXISTING KEY |
1232 | * service action with the SERVICE ACTION RESERVATION KEY | 1232 | * service action with the SERVICE ACTION RESERVATION KEY |
1233 | * field set to zero (see 5.7.11.3). | 1233 | * field set to zero (see 5.7.11.3). |
1234 | */ | 1234 | */ |
1235 | __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0); | 1235 | __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0); |
1236 | ret = 1; | 1236 | ret = 1; |
1237 | /* | 1237 | /* |
1238 | * For 'All Registrants' reservation types, all existing | 1238 | * For 'All Registrants' reservation types, all existing |
1239 | * registrations are still processed as reservation holders | 1239 | * registrations are still processed as reservation holders |
1240 | * in core_scsi3_pr_seq_non_holder() after the initial | 1240 | * in core_scsi3_pr_seq_non_holder() after the initial |
1241 | * reservation holder is implictly released here. | 1241 | * reservation holder is implictly released here. |
1242 | */ | 1242 | */ |
1243 | } else if (pr_reg->pr_reg_all_tg_pt && | 1243 | } else if (pr_reg->pr_reg_all_tg_pt && |
1244 | (!strcmp(pr_res_holder->pr_reg_nacl->initiatorname, | 1244 | (!strcmp(pr_res_holder->pr_reg_nacl->initiatorname, |
1245 | pr_reg->pr_reg_nacl->initiatorname)) && | 1245 | pr_reg->pr_reg_nacl->initiatorname)) && |
1246 | (pr_res_holder->pr_res_key == pr_reg->pr_res_key)) { | 1246 | (pr_res_holder->pr_res_key == pr_reg->pr_res_key)) { |
1247 | pr_err("SPC-3 PR: Unable to perform ALL_TG_PT=1" | 1247 | pr_err("SPC-3 PR: Unable to perform ALL_TG_PT=1" |
1248 | " UNREGISTER while existing reservation with matching" | 1248 | " UNREGISTER while existing reservation with matching" |
1249 | " key 0x%016Lx is present from another SCSI Initiator" | 1249 | " key 0x%016Lx is present from another SCSI Initiator" |
1250 | " Port\n", pr_reg->pr_res_key); | 1250 | " Port\n", pr_reg->pr_res_key); |
1251 | ret = -EPERM; | 1251 | ret = -EPERM; |
1252 | } | 1252 | } |
1253 | spin_unlock(&dev->dev_reservation_lock); | 1253 | spin_unlock(&dev->dev_reservation_lock); |
1254 | 1254 | ||
1255 | return ret; | 1255 | return ret; |
1256 | } | 1256 | } |
1257 | 1257 | ||
1258 | /* | 1258 | /* |
1259 | * Called with struct t10_reservation->registration_lock held. | 1259 | * Called with struct t10_reservation->registration_lock held. |
1260 | */ | 1260 | */ |
1261 | static void __core_scsi3_free_registration( | 1261 | static void __core_scsi3_free_registration( |
1262 | struct se_device *dev, | 1262 | struct se_device *dev, |
1263 | struct t10_pr_registration *pr_reg, | 1263 | struct t10_pr_registration *pr_reg, |
1264 | struct list_head *preempt_and_abort_list, | 1264 | struct list_head *preempt_and_abort_list, |
1265 | int dec_holders) | 1265 | int dec_holders) |
1266 | { | 1266 | { |
1267 | struct target_core_fabric_ops *tfo = | 1267 | struct target_core_fabric_ops *tfo = |
1268 | pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; | 1268 | pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; |
1269 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 1269 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
1270 | char i_buf[PR_REG_ISID_ID_LEN]; | 1270 | char i_buf[PR_REG_ISID_ID_LEN]; |
1271 | int prf_isid; | 1271 | int prf_isid; |
1272 | 1272 | ||
1273 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 1273 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
1274 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 1274 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
1275 | PR_REG_ISID_ID_LEN); | 1275 | PR_REG_ISID_ID_LEN); |
1276 | 1276 | ||
1277 | pr_reg->pr_reg_deve->def_pr_registered = 0; | 1277 | pr_reg->pr_reg_deve->def_pr_registered = 0; |
1278 | pr_reg->pr_reg_deve->pr_res_key = 0; | 1278 | pr_reg->pr_reg_deve->pr_res_key = 0; |
1279 | list_del(&pr_reg->pr_reg_list); | 1279 | list_del(&pr_reg->pr_reg_list); |
1280 | /* | 1280 | /* |
1281 | * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(), | 1281 | * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(), |
1282 | * so call core_scsi3_put_pr_reg() to decrement our reference. | 1282 | * so call core_scsi3_put_pr_reg() to decrement our reference. |
1283 | */ | 1283 | */ |
1284 | if (dec_holders) | 1284 | if (dec_holders) |
1285 | core_scsi3_put_pr_reg(pr_reg); | 1285 | core_scsi3_put_pr_reg(pr_reg); |
1286 | /* | 1286 | /* |
1287 | * Wait until all reference from any other I_T nexuses for this | 1287 | * Wait until all reference from any other I_T nexuses for this |
1288 | * *pr_reg have been released. Because list_del() is called above, | 1288 | * *pr_reg have been released. Because list_del() is called above, |
1289 | * the last core_scsi3_put_pr_reg(pr_reg) will release this reference | 1289 | * the last core_scsi3_put_pr_reg(pr_reg) will release this reference |
1290 | * count back to zero, and we release *pr_reg. | 1290 | * count back to zero, and we release *pr_reg. |
1291 | */ | 1291 | */ |
1292 | while (atomic_read(&pr_reg->pr_res_holders) != 0) { | 1292 | while (atomic_read(&pr_reg->pr_res_holders) != 0) { |
1293 | spin_unlock(&pr_tmpl->registration_lock); | 1293 | spin_unlock(&pr_tmpl->registration_lock); |
1294 | pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", | 1294 | pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", |
1295 | tfo->get_fabric_name()); | 1295 | tfo->get_fabric_name()); |
1296 | cpu_relax(); | 1296 | cpu_relax(); |
1297 | spin_lock(&pr_tmpl->registration_lock); | 1297 | spin_lock(&pr_tmpl->registration_lock); |
1298 | } | 1298 | } |
1299 | 1299 | ||
1300 | pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" | 1300 | pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" |
1301 | " Node: %s%s\n", tfo->get_fabric_name(), | 1301 | " Node: %s%s\n", tfo->get_fabric_name(), |
1302 | pr_reg->pr_reg_nacl->initiatorname, | 1302 | pr_reg->pr_reg_nacl->initiatorname, |
1303 | (prf_isid) ? &i_buf[0] : ""); | 1303 | (prf_isid) ? &i_buf[0] : ""); |
1304 | pr_debug("SPC-3 PR [%s] for %s TCM Subsystem %s Object Target" | 1304 | pr_debug("SPC-3 PR [%s] for %s TCM Subsystem %s Object Target" |
1305 | " Port(s)\n", tfo->get_fabric_name(), | 1305 | " Port(s)\n", tfo->get_fabric_name(), |
1306 | (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", | 1306 | (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", |
1307 | dev->transport->name); | 1307 | dev->transport->name); |
1308 | pr_debug("SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:" | 1308 | pr_debug("SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:" |
1309 | " 0x%08x\n", tfo->get_fabric_name(), pr_reg->pr_res_key, | 1309 | " 0x%08x\n", tfo->get_fabric_name(), pr_reg->pr_res_key, |
1310 | pr_reg->pr_res_generation); | 1310 | pr_reg->pr_res_generation); |
1311 | 1311 | ||
1312 | if (!preempt_and_abort_list) { | 1312 | if (!preempt_and_abort_list) { |
1313 | pr_reg->pr_reg_deve = NULL; | 1313 | pr_reg->pr_reg_deve = NULL; |
1314 | pr_reg->pr_reg_nacl = NULL; | 1314 | pr_reg->pr_reg_nacl = NULL; |
1315 | kfree(pr_reg->pr_aptpl_buf); | 1315 | kfree(pr_reg->pr_aptpl_buf); |
1316 | kmem_cache_free(t10_pr_reg_cache, pr_reg); | 1316 | kmem_cache_free(t10_pr_reg_cache, pr_reg); |
1317 | return; | 1317 | return; |
1318 | } | 1318 | } |
1319 | /* | 1319 | /* |
1320 | * For PREEMPT_AND_ABORT, the list of *pr_reg in preempt_and_abort_list | 1320 | * For PREEMPT_AND_ABORT, the list of *pr_reg in preempt_and_abort_list |
1321 | * are released once the ABORT_TASK_SET has completed.. | 1321 | * are released once the ABORT_TASK_SET has completed.. |
1322 | */ | 1322 | */ |
1323 | list_add_tail(&pr_reg->pr_reg_abort_list, preempt_and_abort_list); | 1323 | list_add_tail(&pr_reg->pr_reg_abort_list, preempt_and_abort_list); |
1324 | } | 1324 | } |
1325 | 1325 | ||
1326 | void core_scsi3_free_pr_reg_from_nacl( | 1326 | void core_scsi3_free_pr_reg_from_nacl( |
1327 | struct se_device *dev, | 1327 | struct se_device *dev, |
1328 | struct se_node_acl *nacl) | 1328 | struct se_node_acl *nacl) |
1329 | { | 1329 | { |
1330 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 1330 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
1331 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; | 1331 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; |
1332 | /* | 1332 | /* |
1333 | * If the passed se_node_acl matches the reservation holder, | 1333 | * If the passed se_node_acl matches the reservation holder, |
1334 | * release the reservation. | 1334 | * release the reservation. |
1335 | */ | 1335 | */ |
1336 | spin_lock(&dev->dev_reservation_lock); | 1336 | spin_lock(&dev->dev_reservation_lock); |
1337 | pr_res_holder = dev->dev_pr_res_holder; | 1337 | pr_res_holder = dev->dev_pr_res_holder; |
1338 | if ((pr_res_holder != NULL) && | 1338 | if ((pr_res_holder != NULL) && |
1339 | (pr_res_holder->pr_reg_nacl == nacl)) | 1339 | (pr_res_holder->pr_reg_nacl == nacl)) |
1340 | __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0); | 1340 | __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0); |
1341 | spin_unlock(&dev->dev_reservation_lock); | 1341 | spin_unlock(&dev->dev_reservation_lock); |
1342 | /* | 1342 | /* |
1343 | * Release any registration associated with the struct se_node_acl. | 1343 | * Release any registration associated with the struct se_node_acl. |
1344 | */ | 1344 | */ |
1345 | spin_lock(&pr_tmpl->registration_lock); | 1345 | spin_lock(&pr_tmpl->registration_lock); |
1346 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 1346 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
1347 | &pr_tmpl->registration_list, pr_reg_list) { | 1347 | &pr_tmpl->registration_list, pr_reg_list) { |
1348 | 1348 | ||
1349 | if (pr_reg->pr_reg_nacl != nacl) | 1349 | if (pr_reg->pr_reg_nacl != nacl) |
1350 | continue; | 1350 | continue; |
1351 | 1351 | ||
1352 | __core_scsi3_free_registration(dev, pr_reg, NULL, 0); | 1352 | __core_scsi3_free_registration(dev, pr_reg, NULL, 0); |
1353 | } | 1353 | } |
1354 | spin_unlock(&pr_tmpl->registration_lock); | 1354 | spin_unlock(&pr_tmpl->registration_lock); |
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | void core_scsi3_free_all_registrations( | 1357 | void core_scsi3_free_all_registrations( |
1358 | struct se_device *dev) | 1358 | struct se_device *dev) |
1359 | { | 1359 | { |
1360 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 1360 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
1361 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; | 1361 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; |
1362 | 1362 | ||
1363 | spin_lock(&dev->dev_reservation_lock); | 1363 | spin_lock(&dev->dev_reservation_lock); |
1364 | pr_res_holder = dev->dev_pr_res_holder; | 1364 | pr_res_holder = dev->dev_pr_res_holder; |
1365 | if (pr_res_holder != NULL) { | 1365 | if (pr_res_holder != NULL) { |
1366 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 1366 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
1367 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, | 1367 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, |
1368 | pr_res_holder, 0); | 1368 | pr_res_holder, 0); |
1369 | } | 1369 | } |
1370 | spin_unlock(&dev->dev_reservation_lock); | 1370 | spin_unlock(&dev->dev_reservation_lock); |
1371 | 1371 | ||
1372 | spin_lock(&pr_tmpl->registration_lock); | 1372 | spin_lock(&pr_tmpl->registration_lock); |
1373 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 1373 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
1374 | &pr_tmpl->registration_list, pr_reg_list) { | 1374 | &pr_tmpl->registration_list, pr_reg_list) { |
1375 | 1375 | ||
1376 | __core_scsi3_free_registration(dev, pr_reg, NULL, 0); | 1376 | __core_scsi3_free_registration(dev, pr_reg, NULL, 0); |
1377 | } | 1377 | } |
1378 | spin_unlock(&pr_tmpl->registration_lock); | 1378 | spin_unlock(&pr_tmpl->registration_lock); |
1379 | 1379 | ||
1380 | spin_lock(&pr_tmpl->aptpl_reg_lock); | 1380 | spin_lock(&pr_tmpl->aptpl_reg_lock); |
1381 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list, | 1381 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list, |
1382 | pr_reg_aptpl_list) { | 1382 | pr_reg_aptpl_list) { |
1383 | list_del(&pr_reg->pr_reg_aptpl_list); | 1383 | list_del(&pr_reg->pr_reg_aptpl_list); |
1384 | kfree(pr_reg->pr_aptpl_buf); | 1384 | kfree(pr_reg->pr_aptpl_buf); |
1385 | kmem_cache_free(t10_pr_reg_cache, pr_reg); | 1385 | kmem_cache_free(t10_pr_reg_cache, pr_reg); |
1386 | } | 1386 | } |
1387 | spin_unlock(&pr_tmpl->aptpl_reg_lock); | 1387 | spin_unlock(&pr_tmpl->aptpl_reg_lock); |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg) | 1390 | static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg) |
1391 | { | 1391 | { |
1392 | return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, | 1392 | return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, |
1393 | &tpg->tpg_group.cg_item); | 1393 | &tpg->tpg_group.cg_item); |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg) | 1396 | static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg) |
1397 | { | 1397 | { |
1398 | configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, | 1398 | configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, |
1399 | &tpg->tpg_group.cg_item); | 1399 | &tpg->tpg_group.cg_item); |
1400 | 1400 | ||
1401 | atomic_dec(&tpg->tpg_pr_ref_count); | 1401 | atomic_dec(&tpg->tpg_pr_ref_count); |
1402 | smp_mb__after_atomic_dec(); | 1402 | smp_mb__after_atomic_dec(); |
1403 | } | 1403 | } |
1404 | 1404 | ||
1405 | static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl) | 1405 | static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl) |
1406 | { | 1406 | { |
1407 | struct se_portal_group *tpg = nacl->se_tpg; | 1407 | struct se_portal_group *tpg = nacl->se_tpg; |
1408 | 1408 | ||
1409 | if (nacl->dynamic_node_acl) | 1409 | if (nacl->dynamic_node_acl) |
1410 | return 0; | 1410 | return 0; |
1411 | 1411 | ||
1412 | return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, | 1412 | return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, |
1413 | &nacl->acl_group.cg_item); | 1413 | &nacl->acl_group.cg_item); |
1414 | } | 1414 | } |
1415 | 1415 | ||
1416 | static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) | 1416 | static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) |
1417 | { | 1417 | { |
1418 | struct se_portal_group *tpg = nacl->se_tpg; | 1418 | struct se_portal_group *tpg = nacl->se_tpg; |
1419 | 1419 | ||
1420 | if (nacl->dynamic_node_acl) { | 1420 | if (nacl->dynamic_node_acl) { |
1421 | atomic_dec(&nacl->acl_pr_ref_count); | 1421 | atomic_dec(&nacl->acl_pr_ref_count); |
1422 | smp_mb__after_atomic_dec(); | 1422 | smp_mb__after_atomic_dec(); |
1423 | return; | 1423 | return; |
1424 | } | 1424 | } |
1425 | 1425 | ||
1426 | configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, | 1426 | configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, |
1427 | &nacl->acl_group.cg_item); | 1427 | &nacl->acl_group.cg_item); |
1428 | 1428 | ||
1429 | atomic_dec(&nacl->acl_pr_ref_count); | 1429 | atomic_dec(&nacl->acl_pr_ref_count); |
1430 | smp_mb__after_atomic_dec(); | 1430 | smp_mb__after_atomic_dec(); |
1431 | } | 1431 | } |
1432 | 1432 | ||
1433 | static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) | 1433 | static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) |
1434 | { | 1434 | { |
1435 | struct se_lun_acl *lun_acl = se_deve->se_lun_acl; | 1435 | struct se_lun_acl *lun_acl = se_deve->se_lun_acl; |
1436 | struct se_node_acl *nacl; | 1436 | struct se_node_acl *nacl; |
1437 | struct se_portal_group *tpg; | 1437 | struct se_portal_group *tpg; |
1438 | /* | 1438 | /* |
1439 | * For nacl->dynamic_node_acl=1 | 1439 | * For nacl->dynamic_node_acl=1 |
1440 | */ | 1440 | */ |
1441 | if (!lun_acl) | 1441 | if (!lun_acl) |
1442 | return 0; | 1442 | return 0; |
1443 | 1443 | ||
1444 | nacl = lun_acl->se_lun_nacl; | 1444 | nacl = lun_acl->se_lun_nacl; |
1445 | tpg = nacl->se_tpg; | 1445 | tpg = nacl->se_tpg; |
1446 | 1446 | ||
1447 | return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, | 1447 | return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, |
1448 | &lun_acl->se_lun_group.cg_item); | 1448 | &lun_acl->se_lun_group.cg_item); |
1449 | } | 1449 | } |
1450 | 1450 | ||
1451 | static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) | 1451 | static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) |
1452 | { | 1452 | { |
1453 | struct se_lun_acl *lun_acl = se_deve->se_lun_acl; | 1453 | struct se_lun_acl *lun_acl = se_deve->se_lun_acl; |
1454 | struct se_node_acl *nacl; | 1454 | struct se_node_acl *nacl; |
1455 | struct se_portal_group *tpg; | 1455 | struct se_portal_group *tpg; |
1456 | /* | 1456 | /* |
1457 | * For nacl->dynamic_node_acl=1 | 1457 | * For nacl->dynamic_node_acl=1 |
1458 | */ | 1458 | */ |
1459 | if (!lun_acl) { | 1459 | if (!lun_acl) { |
1460 | atomic_dec(&se_deve->pr_ref_count); | 1460 | atomic_dec(&se_deve->pr_ref_count); |
1461 | smp_mb__after_atomic_dec(); | 1461 | smp_mb__after_atomic_dec(); |
1462 | return; | 1462 | return; |
1463 | } | 1463 | } |
1464 | nacl = lun_acl->se_lun_nacl; | 1464 | nacl = lun_acl->se_lun_nacl; |
1465 | tpg = nacl->se_tpg; | 1465 | tpg = nacl->se_tpg; |
1466 | 1466 | ||
1467 | configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, | 1467 | configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, |
1468 | &lun_acl->se_lun_group.cg_item); | 1468 | &lun_acl->se_lun_group.cg_item); |
1469 | 1469 | ||
1470 | atomic_dec(&se_deve->pr_ref_count); | 1470 | atomic_dec(&se_deve->pr_ref_count); |
1471 | smp_mb__after_atomic_dec(); | 1471 | smp_mb__after_atomic_dec(); |
1472 | } | 1472 | } |
1473 | 1473 | ||
1474 | static int core_scsi3_decode_spec_i_port( | 1474 | static int core_scsi3_decode_spec_i_port( |
1475 | struct se_cmd *cmd, | 1475 | struct se_cmd *cmd, |
1476 | struct se_portal_group *tpg, | 1476 | struct se_portal_group *tpg, |
1477 | unsigned char *l_isid, | 1477 | unsigned char *l_isid, |
1478 | u64 sa_res_key, | 1478 | u64 sa_res_key, |
1479 | int all_tg_pt, | 1479 | int all_tg_pt, |
1480 | int aptpl) | 1480 | int aptpl) |
1481 | { | 1481 | { |
1482 | struct se_device *dev = cmd->se_dev; | 1482 | struct se_device *dev = cmd->se_dev; |
1483 | struct se_port *tmp_port; | 1483 | struct se_port *tmp_port; |
1484 | struct se_portal_group *dest_tpg = NULL, *tmp_tpg; | 1484 | struct se_portal_group *dest_tpg = NULL, *tmp_tpg; |
1485 | struct se_session *se_sess = cmd->se_sess; | 1485 | struct se_session *se_sess = cmd->se_sess; |
1486 | struct se_node_acl *dest_node_acl = NULL; | 1486 | struct se_node_acl *dest_node_acl = NULL; |
1487 | struct se_dev_entry *dest_se_deve = NULL, *local_se_deve; | 1487 | struct se_dev_entry *dest_se_deve = NULL, *local_se_deve; |
1488 | struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; | 1488 | struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; |
1489 | struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; | 1489 | struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; |
1490 | struct list_head tid_dest_list; | 1490 | LIST_HEAD(tid_dest_list); |
1491 | struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; | 1491 | struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; |
1492 | struct target_core_fabric_ops *tmp_tf_ops; | 1492 | struct target_core_fabric_ops *tmp_tf_ops; |
1493 | unsigned char *buf; | 1493 | unsigned char *buf; |
1494 | unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; | 1494 | unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; |
1495 | char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; | 1495 | char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; |
1496 | u32 tpdl, tid_len = 0; | 1496 | u32 tpdl, tid_len = 0; |
1497 | int ret, dest_local_nexus, prf_isid; | 1497 | int ret, dest_local_nexus, prf_isid; |
1498 | u32 dest_rtpi = 0; | 1498 | u32 dest_rtpi = 0; |
1499 | 1499 | ||
1500 | memset(dest_iport, 0, 64); | 1500 | memset(dest_iport, 0, 64); |
1501 | INIT_LIST_HEAD(&tid_dest_list); | ||
1502 | 1501 | ||
1503 | local_se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; | 1502 | local_se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; |
1504 | /* | 1503 | /* |
1505 | * Allocate a struct pr_transport_id_holder and setup the | 1504 | * Allocate a struct pr_transport_id_holder and setup the |
1506 | * local_node_acl and local_se_deve pointers and add to | 1505 | * local_node_acl and local_se_deve pointers and add to |
1507 | * struct list_head tid_dest_list for add registration | 1506 | * struct list_head tid_dest_list for add registration |
1508 | * processing in the loop of tid_dest_list below. | 1507 | * processing in the loop of tid_dest_list below. |
1509 | */ | 1508 | */ |
1510 | tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); | 1509 | tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); |
1511 | if (!tidh_new) { | 1510 | if (!tidh_new) { |
1512 | pr_err("Unable to allocate tidh_new\n"); | 1511 | pr_err("Unable to allocate tidh_new\n"); |
1513 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1512 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1514 | return -EINVAL; | 1513 | return -EINVAL; |
1515 | } | 1514 | } |
1516 | INIT_LIST_HEAD(&tidh_new->dest_list); | 1515 | INIT_LIST_HEAD(&tidh_new->dest_list); |
1517 | tidh_new->dest_tpg = tpg; | 1516 | tidh_new->dest_tpg = tpg; |
1518 | tidh_new->dest_node_acl = se_sess->se_node_acl; | 1517 | tidh_new->dest_node_acl = se_sess->se_node_acl; |
1519 | tidh_new->dest_se_deve = local_se_deve; | 1518 | tidh_new->dest_se_deve = local_se_deve; |
1520 | 1519 | ||
1521 | local_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, | 1520 | local_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, |
1522 | se_sess->se_node_acl, local_se_deve, l_isid, | 1521 | se_sess->se_node_acl, local_se_deve, l_isid, |
1523 | sa_res_key, all_tg_pt, aptpl); | 1522 | sa_res_key, all_tg_pt, aptpl); |
1524 | if (!local_pr_reg) { | 1523 | if (!local_pr_reg) { |
1525 | kfree(tidh_new); | 1524 | kfree(tidh_new); |
1526 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1525 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1527 | return -ENOMEM; | 1526 | return -ENOMEM; |
1528 | } | 1527 | } |
1529 | tidh_new->dest_pr_reg = local_pr_reg; | 1528 | tidh_new->dest_pr_reg = local_pr_reg; |
1530 | /* | 1529 | /* |
1531 | * The local I_T nexus does not hold any configfs dependances, | 1530 | * The local I_T nexus does not hold any configfs dependances, |
1532 | * so we set tid_h->dest_local_nexus=1 to prevent the | 1531 | * so we set tid_h->dest_local_nexus=1 to prevent the |
1533 | * configfs_undepend_item() calls in the tid_dest_list loops below. | 1532 | * configfs_undepend_item() calls in the tid_dest_list loops below. |
1534 | */ | 1533 | */ |
1535 | tidh_new->dest_local_nexus = 1; | 1534 | tidh_new->dest_local_nexus = 1; |
1536 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); | 1535 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); |
1537 | 1536 | ||
1538 | buf = transport_kmap_data_sg(cmd); | 1537 | buf = transport_kmap_data_sg(cmd); |
1539 | /* | 1538 | /* |
1540 | * For a PERSISTENT RESERVE OUT specify initiator ports payload, | 1539 | * For a PERSISTENT RESERVE OUT specify initiator ports payload, |
1541 | * first extract TransportID Parameter Data Length, and make sure | 1540 | * first extract TransportID Parameter Data Length, and make sure |
1542 | * the value matches up to the SCSI expected data transfer length. | 1541 | * the value matches up to the SCSI expected data transfer length. |
1543 | */ | 1542 | */ |
1544 | tpdl = (buf[24] & 0xff) << 24; | 1543 | tpdl = (buf[24] & 0xff) << 24; |
1545 | tpdl |= (buf[25] & 0xff) << 16; | 1544 | tpdl |= (buf[25] & 0xff) << 16; |
1546 | tpdl |= (buf[26] & 0xff) << 8; | 1545 | tpdl |= (buf[26] & 0xff) << 8; |
1547 | tpdl |= buf[27] & 0xff; | 1546 | tpdl |= buf[27] & 0xff; |
1548 | 1547 | ||
1549 | if ((tpdl + 28) != cmd->data_length) { | 1548 | if ((tpdl + 28) != cmd->data_length) { |
1550 | pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header" | 1549 | pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header" |
1551 | " does not equal CDB data_length: %u\n", tpdl, | 1550 | " does not equal CDB data_length: %u\n", tpdl, |
1552 | cmd->data_length); | 1551 | cmd->data_length); |
1553 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 1552 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
1554 | ret = -EINVAL; | 1553 | ret = -EINVAL; |
1555 | goto out; | 1554 | goto out; |
1556 | } | 1555 | } |
1557 | /* | 1556 | /* |
1558 | * Start processing the received transport IDs using the | 1557 | * Start processing the received transport IDs using the |
1559 | * receiving I_T Nexus portal's fabric dependent methods to | 1558 | * receiving I_T Nexus portal's fabric dependent methods to |
1560 | * obtain the SCSI Initiator Port/Device Identifiers. | 1559 | * obtain the SCSI Initiator Port/Device Identifiers. |
1561 | */ | 1560 | */ |
1562 | ptr = &buf[28]; | 1561 | ptr = &buf[28]; |
1563 | 1562 | ||
1564 | while (tpdl > 0) { | 1563 | while (tpdl > 0) { |
1565 | proto_ident = (ptr[0] & 0x0f); | 1564 | proto_ident = (ptr[0] & 0x0f); |
1566 | dest_tpg = NULL; | 1565 | dest_tpg = NULL; |
1567 | 1566 | ||
1568 | spin_lock(&dev->se_port_lock); | 1567 | spin_lock(&dev->se_port_lock); |
1569 | list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) { | 1568 | list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) { |
1570 | tmp_tpg = tmp_port->sep_tpg; | 1569 | tmp_tpg = tmp_port->sep_tpg; |
1571 | if (!tmp_tpg) | 1570 | if (!tmp_tpg) |
1572 | continue; | 1571 | continue; |
1573 | tmp_tf_ops = tmp_tpg->se_tpg_tfo; | 1572 | tmp_tf_ops = tmp_tpg->se_tpg_tfo; |
1574 | if (!tmp_tf_ops) | 1573 | if (!tmp_tf_ops) |
1575 | continue; | 1574 | continue; |
1576 | if (!tmp_tf_ops->get_fabric_proto_ident || | 1575 | if (!tmp_tf_ops->get_fabric_proto_ident || |
1577 | !tmp_tf_ops->tpg_parse_pr_out_transport_id) | 1576 | !tmp_tf_ops->tpg_parse_pr_out_transport_id) |
1578 | continue; | 1577 | continue; |
1579 | /* | 1578 | /* |
1580 | * Look for the matching proto_ident provided by | 1579 | * Look for the matching proto_ident provided by |
1581 | * the received TransportID | 1580 | * the received TransportID |
1582 | */ | 1581 | */ |
1583 | tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg); | 1582 | tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg); |
1584 | if (tmp_proto_ident != proto_ident) | 1583 | if (tmp_proto_ident != proto_ident) |
1585 | continue; | 1584 | continue; |
1586 | dest_rtpi = tmp_port->sep_rtpi; | 1585 | dest_rtpi = tmp_port->sep_rtpi; |
1587 | 1586 | ||
1588 | i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id( | 1587 | i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id( |
1589 | tmp_tpg, (const char *)ptr, &tid_len, | 1588 | tmp_tpg, (const char *)ptr, &tid_len, |
1590 | &iport_ptr); | 1589 | &iport_ptr); |
1591 | if (!i_str) | 1590 | if (!i_str) |
1592 | continue; | 1591 | continue; |
1593 | 1592 | ||
1594 | atomic_inc(&tmp_tpg->tpg_pr_ref_count); | 1593 | atomic_inc(&tmp_tpg->tpg_pr_ref_count); |
1595 | smp_mb__after_atomic_inc(); | 1594 | smp_mb__after_atomic_inc(); |
1596 | spin_unlock(&dev->se_port_lock); | 1595 | spin_unlock(&dev->se_port_lock); |
1597 | 1596 | ||
1598 | ret = core_scsi3_tpg_depend_item(tmp_tpg); | 1597 | ret = core_scsi3_tpg_depend_item(tmp_tpg); |
1599 | if (ret != 0) { | 1598 | if (ret != 0) { |
1600 | pr_err(" core_scsi3_tpg_depend_item()" | 1599 | pr_err(" core_scsi3_tpg_depend_item()" |
1601 | " for tmp_tpg\n"); | 1600 | " for tmp_tpg\n"); |
1602 | atomic_dec(&tmp_tpg->tpg_pr_ref_count); | 1601 | atomic_dec(&tmp_tpg->tpg_pr_ref_count); |
1603 | smp_mb__after_atomic_dec(); | 1602 | smp_mb__after_atomic_dec(); |
1604 | cmd->scsi_sense_reason = | 1603 | cmd->scsi_sense_reason = |
1605 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1604 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1606 | ret = -EINVAL; | 1605 | ret = -EINVAL; |
1607 | goto out; | 1606 | goto out; |
1608 | } | 1607 | } |
1609 | /* | 1608 | /* |
1610 | * Locate the desination initiator ACL to be registered | 1609 | * Locate the desination initiator ACL to be registered |
1611 | * from the decoded fabric module specific TransportID | 1610 | * from the decoded fabric module specific TransportID |
1612 | * at *i_str. | 1611 | * at *i_str. |
1613 | */ | 1612 | */ |
1614 | spin_lock_irq(&tmp_tpg->acl_node_lock); | 1613 | spin_lock_irq(&tmp_tpg->acl_node_lock); |
1615 | dest_node_acl = __core_tpg_get_initiator_node_acl( | 1614 | dest_node_acl = __core_tpg_get_initiator_node_acl( |
1616 | tmp_tpg, i_str); | 1615 | tmp_tpg, i_str); |
1617 | if (dest_node_acl) { | 1616 | if (dest_node_acl) { |
1618 | atomic_inc(&dest_node_acl->acl_pr_ref_count); | 1617 | atomic_inc(&dest_node_acl->acl_pr_ref_count); |
1619 | smp_mb__after_atomic_inc(); | 1618 | smp_mb__after_atomic_inc(); |
1620 | } | 1619 | } |
1621 | spin_unlock_irq(&tmp_tpg->acl_node_lock); | 1620 | spin_unlock_irq(&tmp_tpg->acl_node_lock); |
1622 | 1621 | ||
1623 | if (!dest_node_acl) { | 1622 | if (!dest_node_acl) { |
1624 | core_scsi3_tpg_undepend_item(tmp_tpg); | 1623 | core_scsi3_tpg_undepend_item(tmp_tpg); |
1625 | spin_lock(&dev->se_port_lock); | 1624 | spin_lock(&dev->se_port_lock); |
1626 | continue; | 1625 | continue; |
1627 | } | 1626 | } |
1628 | 1627 | ||
1629 | ret = core_scsi3_nodeacl_depend_item(dest_node_acl); | 1628 | ret = core_scsi3_nodeacl_depend_item(dest_node_acl); |
1630 | if (ret != 0) { | 1629 | if (ret != 0) { |
1631 | pr_err("configfs_depend_item() failed" | 1630 | pr_err("configfs_depend_item() failed" |
1632 | " for dest_node_acl->acl_group\n"); | 1631 | " for dest_node_acl->acl_group\n"); |
1633 | atomic_dec(&dest_node_acl->acl_pr_ref_count); | 1632 | atomic_dec(&dest_node_acl->acl_pr_ref_count); |
1634 | smp_mb__after_atomic_dec(); | 1633 | smp_mb__after_atomic_dec(); |
1635 | core_scsi3_tpg_undepend_item(tmp_tpg); | 1634 | core_scsi3_tpg_undepend_item(tmp_tpg); |
1636 | cmd->scsi_sense_reason = | 1635 | cmd->scsi_sense_reason = |
1637 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1636 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1638 | ret = -EINVAL; | 1637 | ret = -EINVAL; |
1639 | goto out; | 1638 | goto out; |
1640 | } | 1639 | } |
1641 | 1640 | ||
1642 | dest_tpg = tmp_tpg; | 1641 | dest_tpg = tmp_tpg; |
1643 | pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node:" | 1642 | pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node:" |
1644 | " %s Port RTPI: %hu\n", | 1643 | " %s Port RTPI: %hu\n", |
1645 | dest_tpg->se_tpg_tfo->get_fabric_name(), | 1644 | dest_tpg->se_tpg_tfo->get_fabric_name(), |
1646 | dest_node_acl->initiatorname, dest_rtpi); | 1645 | dest_node_acl->initiatorname, dest_rtpi); |
1647 | 1646 | ||
1648 | spin_lock(&dev->se_port_lock); | 1647 | spin_lock(&dev->se_port_lock); |
1649 | break; | 1648 | break; |
1650 | } | 1649 | } |
1651 | spin_unlock(&dev->se_port_lock); | 1650 | spin_unlock(&dev->se_port_lock); |
1652 | 1651 | ||
1653 | if (!dest_tpg) { | 1652 | if (!dest_tpg) { |
1654 | pr_err("SPC-3 PR SPEC_I_PT: Unable to locate" | 1653 | pr_err("SPC-3 PR SPEC_I_PT: Unable to locate" |
1655 | " dest_tpg\n"); | 1654 | " dest_tpg\n"); |
1656 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 1655 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
1657 | ret = -EINVAL; | 1656 | ret = -EINVAL; |
1658 | goto out; | 1657 | goto out; |
1659 | } | 1658 | } |
1660 | #if 0 | 1659 | #if 0 |
1661 | pr_debug("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u" | 1660 | pr_debug("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u" |
1662 | " tid_len: %d for %s + %s\n", | 1661 | " tid_len: %d for %s + %s\n", |
1663 | dest_tpg->se_tpg_tfo->get_fabric_name(), cmd->data_length, | 1662 | dest_tpg->se_tpg_tfo->get_fabric_name(), cmd->data_length, |
1664 | tpdl, tid_len, i_str, iport_ptr); | 1663 | tpdl, tid_len, i_str, iport_ptr); |
1665 | #endif | 1664 | #endif |
1666 | if (tid_len > tpdl) { | 1665 | if (tid_len > tpdl) { |
1667 | pr_err("SPC-3 PR SPEC_I_PT: Illegal tid_len:" | 1666 | pr_err("SPC-3 PR SPEC_I_PT: Illegal tid_len:" |
1668 | " %u for Transport ID: %s\n", tid_len, ptr); | 1667 | " %u for Transport ID: %s\n", tid_len, ptr); |
1669 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1668 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1670 | core_scsi3_tpg_undepend_item(dest_tpg); | 1669 | core_scsi3_tpg_undepend_item(dest_tpg); |
1671 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 1670 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
1672 | ret = -EINVAL; | 1671 | ret = -EINVAL; |
1673 | goto out; | 1672 | goto out; |
1674 | } | 1673 | } |
1675 | /* | 1674 | /* |
1676 | * Locate the desintation struct se_dev_entry pointer for matching | 1675 | * Locate the desintation struct se_dev_entry pointer for matching |
1677 | * RELATIVE TARGET PORT IDENTIFIER on the receiving I_T Nexus | 1676 | * RELATIVE TARGET PORT IDENTIFIER on the receiving I_T Nexus |
1678 | * Target Port. | 1677 | * Target Port. |
1679 | */ | 1678 | */ |
1680 | dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, | 1679 | dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, |
1681 | dest_rtpi); | 1680 | dest_rtpi); |
1682 | if (!dest_se_deve) { | 1681 | if (!dest_se_deve) { |
1683 | pr_err("Unable to locate %s dest_se_deve" | 1682 | pr_err("Unable to locate %s dest_se_deve" |
1684 | " from destination RTPI: %hu\n", | 1683 | " from destination RTPI: %hu\n", |
1685 | dest_tpg->se_tpg_tfo->get_fabric_name(), | 1684 | dest_tpg->se_tpg_tfo->get_fabric_name(), |
1686 | dest_rtpi); | 1685 | dest_rtpi); |
1687 | 1686 | ||
1688 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1687 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1689 | core_scsi3_tpg_undepend_item(dest_tpg); | 1688 | core_scsi3_tpg_undepend_item(dest_tpg); |
1690 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 1689 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
1691 | ret = -EINVAL; | 1690 | ret = -EINVAL; |
1692 | goto out; | 1691 | goto out; |
1693 | } | 1692 | } |
1694 | 1693 | ||
1695 | ret = core_scsi3_lunacl_depend_item(dest_se_deve); | 1694 | ret = core_scsi3_lunacl_depend_item(dest_se_deve); |
1696 | if (ret < 0) { | 1695 | if (ret < 0) { |
1697 | pr_err("core_scsi3_lunacl_depend_item()" | 1696 | pr_err("core_scsi3_lunacl_depend_item()" |
1698 | " failed\n"); | 1697 | " failed\n"); |
1699 | atomic_dec(&dest_se_deve->pr_ref_count); | 1698 | atomic_dec(&dest_se_deve->pr_ref_count); |
1700 | smp_mb__after_atomic_dec(); | 1699 | smp_mb__after_atomic_dec(); |
1701 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1700 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1702 | core_scsi3_tpg_undepend_item(dest_tpg); | 1701 | core_scsi3_tpg_undepend_item(dest_tpg); |
1703 | cmd->scsi_sense_reason = | 1702 | cmd->scsi_sense_reason = |
1704 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1703 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1705 | ret = -EINVAL; | 1704 | ret = -EINVAL; |
1706 | goto out; | 1705 | goto out; |
1707 | } | 1706 | } |
1708 | #if 0 | 1707 | #if 0 |
1709 | pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" | 1708 | pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" |
1710 | " dest_se_deve mapped_lun: %u\n", | 1709 | " dest_se_deve mapped_lun: %u\n", |
1711 | dest_tpg->se_tpg_tfo->get_fabric_name(), | 1710 | dest_tpg->se_tpg_tfo->get_fabric_name(), |
1712 | dest_node_acl->initiatorname, dest_se_deve->mapped_lun); | 1711 | dest_node_acl->initiatorname, dest_se_deve->mapped_lun); |
1713 | #endif | 1712 | #endif |
1714 | /* | 1713 | /* |
1715 | * Skip any TransportIDs that already have a registration for | 1714 | * Skip any TransportIDs that already have a registration for |
1716 | * this target port. | 1715 | * this target port. |
1717 | */ | 1716 | */ |
1718 | pr_reg_e = __core_scsi3_locate_pr_reg(dev, dest_node_acl, | 1717 | pr_reg_e = __core_scsi3_locate_pr_reg(dev, dest_node_acl, |
1719 | iport_ptr); | 1718 | iport_ptr); |
1720 | if (pr_reg_e) { | 1719 | if (pr_reg_e) { |
1721 | core_scsi3_put_pr_reg(pr_reg_e); | 1720 | core_scsi3_put_pr_reg(pr_reg_e); |
1722 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1721 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1723 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1722 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1724 | core_scsi3_tpg_undepend_item(dest_tpg); | 1723 | core_scsi3_tpg_undepend_item(dest_tpg); |
1725 | ptr += tid_len; | 1724 | ptr += tid_len; |
1726 | tpdl -= tid_len; | 1725 | tpdl -= tid_len; |
1727 | tid_len = 0; | 1726 | tid_len = 0; |
1728 | continue; | 1727 | continue; |
1729 | } | 1728 | } |
1730 | /* | 1729 | /* |
1731 | * Allocate a struct pr_transport_id_holder and setup | 1730 | * Allocate a struct pr_transport_id_holder and setup |
1732 | * the dest_node_acl and dest_se_deve pointers for the | 1731 | * the dest_node_acl and dest_se_deve pointers for the |
1733 | * loop below. | 1732 | * loop below. |
1734 | */ | 1733 | */ |
1735 | tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), | 1734 | tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), |
1736 | GFP_KERNEL); | 1735 | GFP_KERNEL); |
1737 | if (!tidh_new) { | 1736 | if (!tidh_new) { |
1738 | pr_err("Unable to allocate tidh_new\n"); | 1737 | pr_err("Unable to allocate tidh_new\n"); |
1739 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1738 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1740 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1739 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1741 | core_scsi3_tpg_undepend_item(dest_tpg); | 1740 | core_scsi3_tpg_undepend_item(dest_tpg); |
1742 | cmd->scsi_sense_reason = | 1741 | cmd->scsi_sense_reason = |
1743 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1742 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1744 | ret = -ENOMEM; | 1743 | ret = -ENOMEM; |
1745 | goto out; | 1744 | goto out; |
1746 | } | 1745 | } |
1747 | INIT_LIST_HEAD(&tidh_new->dest_list); | 1746 | INIT_LIST_HEAD(&tidh_new->dest_list); |
1748 | tidh_new->dest_tpg = dest_tpg; | 1747 | tidh_new->dest_tpg = dest_tpg; |
1749 | tidh_new->dest_node_acl = dest_node_acl; | 1748 | tidh_new->dest_node_acl = dest_node_acl; |
1750 | tidh_new->dest_se_deve = dest_se_deve; | 1749 | tidh_new->dest_se_deve = dest_se_deve; |
1751 | 1750 | ||
1752 | /* | 1751 | /* |
1753 | * Allocate, but do NOT add the registration for the | 1752 | * Allocate, but do NOT add the registration for the |
1754 | * TransportID referenced SCSI Initiator port. This | 1753 | * TransportID referenced SCSI Initiator port. This |
1755 | * done because of the following from spc4r17 in section | 1754 | * done because of the following from spc4r17 in section |
1756 | * 6.14.3 wrt SPEC_I_PT: | 1755 | * 6.14.3 wrt SPEC_I_PT: |
1757 | * | 1756 | * |
1758 | * "If a registration fails for any initiator port (e.g., if th | 1757 | * "If a registration fails for any initiator port (e.g., if th |
1759 | * logical unit does not have enough resources available to | 1758 | * logical unit does not have enough resources available to |
1760 | * hold the registration information), no registrations shall be | 1759 | * hold the registration information), no registrations shall be |
1761 | * made, and the command shall be terminated with | 1760 | * made, and the command shall be terminated with |
1762 | * CHECK CONDITION status." | 1761 | * CHECK CONDITION status." |
1763 | * | 1762 | * |
1764 | * That means we call __core_scsi3_alloc_registration() here, | 1763 | * That means we call __core_scsi3_alloc_registration() here, |
1765 | * and then call __core_scsi3_add_registration() in the | 1764 | * and then call __core_scsi3_add_registration() in the |
1766 | * 2nd loop which will never fail. | 1765 | * 2nd loop which will never fail. |
1767 | */ | 1766 | */ |
1768 | dest_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, | 1767 | dest_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, |
1769 | dest_node_acl, dest_se_deve, iport_ptr, | 1768 | dest_node_acl, dest_se_deve, iport_ptr, |
1770 | sa_res_key, all_tg_pt, aptpl); | 1769 | sa_res_key, all_tg_pt, aptpl); |
1771 | if (!dest_pr_reg) { | 1770 | if (!dest_pr_reg) { |
1772 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1771 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1773 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1772 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1774 | core_scsi3_tpg_undepend_item(dest_tpg); | 1773 | core_scsi3_tpg_undepend_item(dest_tpg); |
1775 | kfree(tidh_new); | 1774 | kfree(tidh_new); |
1776 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 1775 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
1777 | ret = -EINVAL; | 1776 | ret = -EINVAL; |
1778 | goto out; | 1777 | goto out; |
1779 | } | 1778 | } |
1780 | tidh_new->dest_pr_reg = dest_pr_reg; | 1779 | tidh_new->dest_pr_reg = dest_pr_reg; |
1781 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); | 1780 | list_add_tail(&tidh_new->dest_list, &tid_dest_list); |
1782 | 1781 | ||
1783 | ptr += tid_len; | 1782 | ptr += tid_len; |
1784 | tpdl -= tid_len; | 1783 | tpdl -= tid_len; |
1785 | tid_len = 0; | 1784 | tid_len = 0; |
1786 | 1785 | ||
1787 | } | 1786 | } |
1788 | 1787 | ||
1789 | transport_kunmap_data_sg(cmd); | 1788 | transport_kunmap_data_sg(cmd); |
1790 | 1789 | ||
1791 | /* | 1790 | /* |
1792 | * Go ahead and create a registrations from tid_dest_list for the | 1791 | * Go ahead and create a registrations from tid_dest_list for the |
1793 | * SPEC_I_PT provided TransportID for the *tidh referenced dest_node_acl | 1792 | * SPEC_I_PT provided TransportID for the *tidh referenced dest_node_acl |
1794 | * and dest_se_deve. | 1793 | * and dest_se_deve. |
1795 | * | 1794 | * |
1796 | * The SA Reservation Key from the PROUT is set for the | 1795 | * The SA Reservation Key from the PROUT is set for the |
1797 | * registration, and ALL_TG_PT is also passed. ALL_TG_PT=1 | 1796 | * registration, and ALL_TG_PT is also passed. ALL_TG_PT=1 |
1798 | * means that the TransportID Initiator port will be | 1797 | * means that the TransportID Initiator port will be |
1799 | * registered on all of the target ports in the SCSI target device | 1798 | * registered on all of the target ports in the SCSI target device |
1800 | * ALL_TG_PT=0 means the registration will only be for the | 1799 | * ALL_TG_PT=0 means the registration will only be for the |
1801 | * SCSI target port the PROUT REGISTER with SPEC_I_PT=1 | 1800 | * SCSI target port the PROUT REGISTER with SPEC_I_PT=1 |
1802 | * was received. | 1801 | * was received. |
1803 | */ | 1802 | */ |
1804 | list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) { | 1803 | list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) { |
1805 | dest_tpg = tidh->dest_tpg; | 1804 | dest_tpg = tidh->dest_tpg; |
1806 | dest_node_acl = tidh->dest_node_acl; | 1805 | dest_node_acl = tidh->dest_node_acl; |
1807 | dest_se_deve = tidh->dest_se_deve; | 1806 | dest_se_deve = tidh->dest_se_deve; |
1808 | dest_pr_reg = tidh->dest_pr_reg; | 1807 | dest_pr_reg = tidh->dest_pr_reg; |
1809 | dest_local_nexus = tidh->dest_local_nexus; | 1808 | dest_local_nexus = tidh->dest_local_nexus; |
1810 | 1809 | ||
1811 | list_del(&tidh->dest_list); | 1810 | list_del(&tidh->dest_list); |
1812 | kfree(tidh); | 1811 | kfree(tidh); |
1813 | 1812 | ||
1814 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 1813 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
1815 | prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0], | 1814 | prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0], |
1816 | PR_REG_ISID_ID_LEN); | 1815 | PR_REG_ISID_ID_LEN); |
1817 | 1816 | ||
1818 | __core_scsi3_add_registration(cmd->se_dev, dest_node_acl, | 1817 | __core_scsi3_add_registration(cmd->se_dev, dest_node_acl, |
1819 | dest_pr_reg, 0, 0); | 1818 | dest_pr_reg, 0, 0); |
1820 | 1819 | ||
1821 | pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully" | 1820 | pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully" |
1822 | " registered Transport ID for Node: %s%s Mapped LUN:" | 1821 | " registered Transport ID for Node: %s%s Mapped LUN:" |
1823 | " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), | 1822 | " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), |
1824 | dest_node_acl->initiatorname, (prf_isid) ? | 1823 | dest_node_acl->initiatorname, (prf_isid) ? |
1825 | &i_buf[0] : "", dest_se_deve->mapped_lun); | 1824 | &i_buf[0] : "", dest_se_deve->mapped_lun); |
1826 | 1825 | ||
1827 | if (dest_local_nexus) | 1826 | if (dest_local_nexus) |
1828 | continue; | 1827 | continue; |
1829 | 1828 | ||
1830 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1829 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1831 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1830 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1832 | core_scsi3_tpg_undepend_item(dest_tpg); | 1831 | core_scsi3_tpg_undepend_item(dest_tpg); |
1833 | } | 1832 | } |
1834 | 1833 | ||
1835 | return 0; | 1834 | return 0; |
1836 | out: | 1835 | out: |
1837 | transport_kunmap_data_sg(cmd); | 1836 | transport_kunmap_data_sg(cmd); |
1838 | /* | 1837 | /* |
1839 | * For the failure case, release everything from tid_dest_list | 1838 | * For the failure case, release everything from tid_dest_list |
1840 | * including *dest_pr_reg and the configfs dependances.. | 1839 | * including *dest_pr_reg and the configfs dependances.. |
1841 | */ | 1840 | */ |
1842 | list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) { | 1841 | list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) { |
1843 | dest_tpg = tidh->dest_tpg; | 1842 | dest_tpg = tidh->dest_tpg; |
1844 | dest_node_acl = tidh->dest_node_acl; | 1843 | dest_node_acl = tidh->dest_node_acl; |
1845 | dest_se_deve = tidh->dest_se_deve; | 1844 | dest_se_deve = tidh->dest_se_deve; |
1846 | dest_pr_reg = tidh->dest_pr_reg; | 1845 | dest_pr_reg = tidh->dest_pr_reg; |
1847 | dest_local_nexus = tidh->dest_local_nexus; | 1846 | dest_local_nexus = tidh->dest_local_nexus; |
1848 | 1847 | ||
1849 | list_del(&tidh->dest_list); | 1848 | list_del(&tidh->dest_list); |
1850 | kfree(tidh); | 1849 | kfree(tidh); |
1851 | /* | 1850 | /* |
1852 | * Release any extra ALL_TG_PT=1 registrations for | 1851 | * Release any extra ALL_TG_PT=1 registrations for |
1853 | * the SPEC_I_PT=1 case. | 1852 | * the SPEC_I_PT=1 case. |
1854 | */ | 1853 | */ |
1855 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, | 1854 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, |
1856 | &dest_pr_reg->pr_reg_atp_list, | 1855 | &dest_pr_reg->pr_reg_atp_list, |
1857 | pr_reg_atp_mem_list) { | 1856 | pr_reg_atp_mem_list) { |
1858 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); | 1857 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); |
1859 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); | 1858 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); |
1860 | kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp); | 1859 | kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp); |
1861 | } | 1860 | } |
1862 | 1861 | ||
1863 | kfree(dest_pr_reg->pr_aptpl_buf); | 1862 | kfree(dest_pr_reg->pr_aptpl_buf); |
1864 | kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); | 1863 | kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); |
1865 | 1864 | ||
1866 | if (dest_local_nexus) | 1865 | if (dest_local_nexus) |
1867 | continue; | 1866 | continue; |
1868 | 1867 | ||
1869 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1868 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1870 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1869 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1871 | core_scsi3_tpg_undepend_item(dest_tpg); | 1870 | core_scsi3_tpg_undepend_item(dest_tpg); |
1872 | } | 1871 | } |
1873 | return ret; | 1872 | return ret; |
1874 | } | 1873 | } |
1875 | 1874 | ||
1876 | /* | 1875 | /* |
1877 | * Called with struct se_device->dev_reservation_lock held | 1876 | * Called with struct se_device->dev_reservation_lock held |
1878 | */ | 1877 | */ |
1879 | static int __core_scsi3_update_aptpl_buf( | 1878 | static int __core_scsi3_update_aptpl_buf( |
1880 | struct se_device *dev, | 1879 | struct se_device *dev, |
1881 | unsigned char *buf, | 1880 | unsigned char *buf, |
1882 | u32 pr_aptpl_buf_len, | 1881 | u32 pr_aptpl_buf_len, |
1883 | int clear_aptpl_metadata) | 1882 | int clear_aptpl_metadata) |
1884 | { | 1883 | { |
1885 | struct se_lun *lun; | 1884 | struct se_lun *lun; |
1886 | struct se_portal_group *tpg; | 1885 | struct se_portal_group *tpg; |
1887 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; | 1886 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; |
1888 | struct t10_pr_registration *pr_reg; | 1887 | struct t10_pr_registration *pr_reg; |
1889 | unsigned char tmp[512], isid_buf[32]; | 1888 | unsigned char tmp[512], isid_buf[32]; |
1890 | ssize_t len = 0; | 1889 | ssize_t len = 0; |
1891 | int reg_count = 0; | 1890 | int reg_count = 0; |
1892 | 1891 | ||
1893 | memset(buf, 0, pr_aptpl_buf_len); | 1892 | memset(buf, 0, pr_aptpl_buf_len); |
1894 | /* | 1893 | /* |
1895 | * Called to clear metadata once APTPL has been deactivated. | 1894 | * Called to clear metadata once APTPL has been deactivated. |
1896 | */ | 1895 | */ |
1897 | if (clear_aptpl_metadata) { | 1896 | if (clear_aptpl_metadata) { |
1898 | snprintf(buf, pr_aptpl_buf_len, | 1897 | snprintf(buf, pr_aptpl_buf_len, |
1899 | "No Registrations or Reservations\n"); | 1898 | "No Registrations or Reservations\n"); |
1900 | return 0; | 1899 | return 0; |
1901 | } | 1900 | } |
1902 | /* | 1901 | /* |
1903 | * Walk the registration list.. | 1902 | * Walk the registration list.. |
1904 | */ | 1903 | */ |
1905 | spin_lock(&su_dev->t10_pr.registration_lock); | 1904 | spin_lock(&su_dev->t10_pr.registration_lock); |
1906 | list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, | 1905 | list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, |
1907 | pr_reg_list) { | 1906 | pr_reg_list) { |
1908 | 1907 | ||
1909 | tmp[0] = '\0'; | 1908 | tmp[0] = '\0'; |
1910 | isid_buf[0] = '\0'; | 1909 | isid_buf[0] = '\0'; |
1911 | tpg = pr_reg->pr_reg_nacl->se_tpg; | 1910 | tpg = pr_reg->pr_reg_nacl->se_tpg; |
1912 | lun = pr_reg->pr_reg_tg_pt_lun; | 1911 | lun = pr_reg->pr_reg_tg_pt_lun; |
1913 | /* | 1912 | /* |
1914 | * Write out any ISID value to APTPL metadata that was included | 1913 | * Write out any ISID value to APTPL metadata that was included |
1915 | * in the original registration. | 1914 | * in the original registration. |
1916 | */ | 1915 | */ |
1917 | if (pr_reg->isid_present_at_reg) | 1916 | if (pr_reg->isid_present_at_reg) |
1918 | snprintf(isid_buf, 32, "initiator_sid=%s\n", | 1917 | snprintf(isid_buf, 32, "initiator_sid=%s\n", |
1919 | pr_reg->pr_reg_isid); | 1918 | pr_reg->pr_reg_isid); |
1920 | /* | 1919 | /* |
1921 | * Include special metadata if the pr_reg matches the | 1920 | * Include special metadata if the pr_reg matches the |
1922 | * reservation holder. | 1921 | * reservation holder. |
1923 | */ | 1922 | */ |
1924 | if (dev->dev_pr_res_holder == pr_reg) { | 1923 | if (dev->dev_pr_res_holder == pr_reg) { |
1925 | snprintf(tmp, 512, "PR_REG_START: %d" | 1924 | snprintf(tmp, 512, "PR_REG_START: %d" |
1926 | "\ninitiator_fabric=%s\n" | 1925 | "\ninitiator_fabric=%s\n" |
1927 | "initiator_node=%s\n%s" | 1926 | "initiator_node=%s\n%s" |
1928 | "sa_res_key=%llu\n" | 1927 | "sa_res_key=%llu\n" |
1929 | "res_holder=1\nres_type=%02x\n" | 1928 | "res_holder=1\nres_type=%02x\n" |
1930 | "res_scope=%02x\nres_all_tg_pt=%d\n" | 1929 | "res_scope=%02x\nres_all_tg_pt=%d\n" |
1931 | "mapped_lun=%u\n", reg_count, | 1930 | "mapped_lun=%u\n", reg_count, |
1932 | tpg->se_tpg_tfo->get_fabric_name(), | 1931 | tpg->se_tpg_tfo->get_fabric_name(), |
1933 | pr_reg->pr_reg_nacl->initiatorname, isid_buf, | 1932 | pr_reg->pr_reg_nacl->initiatorname, isid_buf, |
1934 | pr_reg->pr_res_key, pr_reg->pr_res_type, | 1933 | pr_reg->pr_res_key, pr_reg->pr_res_type, |
1935 | pr_reg->pr_res_scope, pr_reg->pr_reg_all_tg_pt, | 1934 | pr_reg->pr_res_scope, pr_reg->pr_reg_all_tg_pt, |
1936 | pr_reg->pr_res_mapped_lun); | 1935 | pr_reg->pr_res_mapped_lun); |
1937 | } else { | 1936 | } else { |
1938 | snprintf(tmp, 512, "PR_REG_START: %d\n" | 1937 | snprintf(tmp, 512, "PR_REG_START: %d\n" |
1939 | "initiator_fabric=%s\ninitiator_node=%s\n%s" | 1938 | "initiator_fabric=%s\ninitiator_node=%s\n%s" |
1940 | "sa_res_key=%llu\nres_holder=0\n" | 1939 | "sa_res_key=%llu\nres_holder=0\n" |
1941 | "res_all_tg_pt=%d\nmapped_lun=%u\n", | 1940 | "res_all_tg_pt=%d\nmapped_lun=%u\n", |
1942 | reg_count, tpg->se_tpg_tfo->get_fabric_name(), | 1941 | reg_count, tpg->se_tpg_tfo->get_fabric_name(), |
1943 | pr_reg->pr_reg_nacl->initiatorname, isid_buf, | 1942 | pr_reg->pr_reg_nacl->initiatorname, isid_buf, |
1944 | pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt, | 1943 | pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt, |
1945 | pr_reg->pr_res_mapped_lun); | 1944 | pr_reg->pr_res_mapped_lun); |
1946 | } | 1945 | } |
1947 | 1946 | ||
1948 | if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { | 1947 | if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { |
1949 | pr_err("Unable to update renaming" | 1948 | pr_err("Unable to update renaming" |
1950 | " APTPL metadata\n"); | 1949 | " APTPL metadata\n"); |
1951 | spin_unlock(&su_dev->t10_pr.registration_lock); | 1950 | spin_unlock(&su_dev->t10_pr.registration_lock); |
1952 | return -EMSGSIZE; | 1951 | return -EMSGSIZE; |
1953 | } | 1952 | } |
1954 | len += sprintf(buf+len, "%s", tmp); | 1953 | len += sprintf(buf+len, "%s", tmp); |
1955 | 1954 | ||
1956 | /* | 1955 | /* |
1957 | * Include information about the associated SCSI target port. | 1956 | * Include information about the associated SCSI target port. |
1958 | */ | 1957 | */ |
1959 | snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n" | 1958 | snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n" |
1960 | "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:" | 1959 | "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:" |
1961 | " %d\n", tpg->se_tpg_tfo->get_fabric_name(), | 1960 | " %d\n", tpg->se_tpg_tfo->get_fabric_name(), |
1962 | tpg->se_tpg_tfo->tpg_get_wwn(tpg), | 1961 | tpg->se_tpg_tfo->tpg_get_wwn(tpg), |
1963 | tpg->se_tpg_tfo->tpg_get_tag(tpg), | 1962 | tpg->se_tpg_tfo->tpg_get_tag(tpg), |
1964 | lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); | 1963 | lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); |
1965 | 1964 | ||
1966 | if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { | 1965 | if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { |
1967 | pr_err("Unable to update renaming" | 1966 | pr_err("Unable to update renaming" |
1968 | " APTPL metadata\n"); | 1967 | " APTPL metadata\n"); |
1969 | spin_unlock(&su_dev->t10_pr.registration_lock); | 1968 | spin_unlock(&su_dev->t10_pr.registration_lock); |
1970 | return -EMSGSIZE; | 1969 | return -EMSGSIZE; |
1971 | } | 1970 | } |
1972 | len += sprintf(buf+len, "%s", tmp); | 1971 | len += sprintf(buf+len, "%s", tmp); |
1973 | reg_count++; | 1972 | reg_count++; |
1974 | } | 1973 | } |
1975 | spin_unlock(&su_dev->t10_pr.registration_lock); | 1974 | spin_unlock(&su_dev->t10_pr.registration_lock); |
1976 | 1975 | ||
1977 | if (!reg_count) | 1976 | if (!reg_count) |
1978 | len += sprintf(buf+len, "No Registrations or Reservations"); | 1977 | len += sprintf(buf+len, "No Registrations or Reservations"); |
1979 | 1978 | ||
1980 | return 0; | 1979 | return 0; |
1981 | } | 1980 | } |
1982 | 1981 | ||
1983 | static int core_scsi3_update_aptpl_buf( | 1982 | static int core_scsi3_update_aptpl_buf( |
1984 | struct se_device *dev, | 1983 | struct se_device *dev, |
1985 | unsigned char *buf, | 1984 | unsigned char *buf, |
1986 | u32 pr_aptpl_buf_len, | 1985 | u32 pr_aptpl_buf_len, |
1987 | int clear_aptpl_metadata) | 1986 | int clear_aptpl_metadata) |
1988 | { | 1987 | { |
1989 | int ret; | 1988 | int ret; |
1990 | 1989 | ||
1991 | spin_lock(&dev->dev_reservation_lock); | 1990 | spin_lock(&dev->dev_reservation_lock); |
1992 | ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, | 1991 | ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, |
1993 | clear_aptpl_metadata); | 1992 | clear_aptpl_metadata); |
1994 | spin_unlock(&dev->dev_reservation_lock); | 1993 | spin_unlock(&dev->dev_reservation_lock); |
1995 | 1994 | ||
1996 | return ret; | 1995 | return ret; |
1997 | } | 1996 | } |
1998 | 1997 | ||
1999 | /* | 1998 | /* |
2000 | * Called with struct se_device->aptpl_file_mutex held | 1999 | * Called with struct se_device->aptpl_file_mutex held |
2001 | */ | 2000 | */ |
2002 | static int __core_scsi3_write_aptpl_to_file( | 2001 | static int __core_scsi3_write_aptpl_to_file( |
2003 | struct se_device *dev, | 2002 | struct se_device *dev, |
2004 | unsigned char *buf, | 2003 | unsigned char *buf, |
2005 | u32 pr_aptpl_buf_len) | 2004 | u32 pr_aptpl_buf_len) |
2006 | { | 2005 | { |
2007 | struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; | 2006 | struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; |
2008 | struct file *file; | 2007 | struct file *file; |
2009 | struct iovec iov[1]; | 2008 | struct iovec iov[1]; |
2010 | mm_segment_t old_fs; | 2009 | mm_segment_t old_fs; |
2011 | int flags = O_RDWR | O_CREAT | O_TRUNC; | 2010 | int flags = O_RDWR | O_CREAT | O_TRUNC; |
2012 | char path[512]; | 2011 | char path[512]; |
2013 | int ret; | 2012 | int ret; |
2014 | 2013 | ||
2015 | memset(iov, 0, sizeof(struct iovec)); | 2014 | memset(iov, 0, sizeof(struct iovec)); |
2016 | memset(path, 0, 512); | 2015 | memset(path, 0, 512); |
2017 | 2016 | ||
2018 | if (strlen(&wwn->unit_serial[0]) >= 512) { | 2017 | if (strlen(&wwn->unit_serial[0]) >= 512) { |
2019 | pr_err("WWN value for struct se_device does not fit" | 2018 | pr_err("WWN value for struct se_device does not fit" |
2020 | " into path buffer\n"); | 2019 | " into path buffer\n"); |
2021 | return -EMSGSIZE; | 2020 | return -EMSGSIZE; |
2022 | } | 2021 | } |
2023 | 2022 | ||
2024 | snprintf(path, 512, "/var/target/pr/aptpl_%s", &wwn->unit_serial[0]); | 2023 | snprintf(path, 512, "/var/target/pr/aptpl_%s", &wwn->unit_serial[0]); |
2025 | file = filp_open(path, flags, 0600); | 2024 | file = filp_open(path, flags, 0600); |
2026 | if (IS_ERR(file) || !file || !file->f_dentry) { | 2025 | if (IS_ERR(file) || !file || !file->f_dentry) { |
2027 | pr_err("filp_open(%s) for APTPL metadata" | 2026 | pr_err("filp_open(%s) for APTPL metadata" |
2028 | " failed\n", path); | 2027 | " failed\n", path); |
2029 | return (PTR_ERR(file) < 0 ? PTR_ERR(file) : -ENOENT); | 2028 | return (PTR_ERR(file) < 0 ? PTR_ERR(file) : -ENOENT); |
2030 | } | 2029 | } |
2031 | 2030 | ||
2032 | iov[0].iov_base = &buf[0]; | 2031 | iov[0].iov_base = &buf[0]; |
2033 | if (!pr_aptpl_buf_len) | 2032 | if (!pr_aptpl_buf_len) |
2034 | iov[0].iov_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */ | 2033 | iov[0].iov_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */ |
2035 | else | 2034 | else |
2036 | iov[0].iov_len = pr_aptpl_buf_len; | 2035 | iov[0].iov_len = pr_aptpl_buf_len; |
2037 | 2036 | ||
2038 | old_fs = get_fs(); | 2037 | old_fs = get_fs(); |
2039 | set_fs(get_ds()); | 2038 | set_fs(get_ds()); |
2040 | ret = vfs_writev(file, &iov[0], 1, &file->f_pos); | 2039 | ret = vfs_writev(file, &iov[0], 1, &file->f_pos); |
2041 | set_fs(old_fs); | 2040 | set_fs(old_fs); |
2042 | 2041 | ||
2043 | if (ret < 0) { | 2042 | if (ret < 0) { |
2044 | pr_debug("Error writing APTPL metadata file: %s\n", path); | 2043 | pr_debug("Error writing APTPL metadata file: %s\n", path); |
2045 | filp_close(file, NULL); | 2044 | filp_close(file, NULL); |
2046 | return -EIO; | 2045 | return -EIO; |
2047 | } | 2046 | } |
2048 | filp_close(file, NULL); | 2047 | filp_close(file, NULL); |
2049 | 2048 | ||
2050 | return 0; | 2049 | return 0; |
2051 | } | 2050 | } |
2052 | 2051 | ||
2053 | static int core_scsi3_update_and_write_aptpl( | 2052 | static int core_scsi3_update_and_write_aptpl( |
2054 | struct se_device *dev, | 2053 | struct se_device *dev, |
2055 | unsigned char *in_buf, | 2054 | unsigned char *in_buf, |
2056 | u32 in_pr_aptpl_buf_len) | 2055 | u32 in_pr_aptpl_buf_len) |
2057 | { | 2056 | { |
2058 | unsigned char null_buf[64], *buf; | 2057 | unsigned char null_buf[64], *buf; |
2059 | u32 pr_aptpl_buf_len; | 2058 | u32 pr_aptpl_buf_len; |
2060 | int ret, clear_aptpl_metadata = 0; | 2059 | int ret, clear_aptpl_metadata = 0; |
2061 | /* | 2060 | /* |
2062 | * Can be called with a NULL pointer from PROUT service action CLEAR | 2061 | * Can be called with a NULL pointer from PROUT service action CLEAR |
2063 | */ | 2062 | */ |
2064 | if (!in_buf) { | 2063 | if (!in_buf) { |
2065 | memset(null_buf, 0, 64); | 2064 | memset(null_buf, 0, 64); |
2066 | buf = &null_buf[0]; | 2065 | buf = &null_buf[0]; |
2067 | /* | 2066 | /* |
2068 | * This will clear the APTPL metadata to: | 2067 | * This will clear the APTPL metadata to: |
2069 | * "No Registrations or Reservations" status | 2068 | * "No Registrations or Reservations" status |
2070 | */ | 2069 | */ |
2071 | pr_aptpl_buf_len = 64; | 2070 | pr_aptpl_buf_len = 64; |
2072 | clear_aptpl_metadata = 1; | 2071 | clear_aptpl_metadata = 1; |
2073 | } else { | 2072 | } else { |
2074 | buf = in_buf; | 2073 | buf = in_buf; |
2075 | pr_aptpl_buf_len = in_pr_aptpl_buf_len; | 2074 | pr_aptpl_buf_len = in_pr_aptpl_buf_len; |
2076 | } | 2075 | } |
2077 | 2076 | ||
2078 | ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, | 2077 | ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, |
2079 | clear_aptpl_metadata); | 2078 | clear_aptpl_metadata); |
2080 | if (ret != 0) | 2079 | if (ret != 0) |
2081 | return ret; | 2080 | return ret; |
2082 | /* | 2081 | /* |
2083 | * __core_scsi3_write_aptpl_to_file() will call strlen() | 2082 | * __core_scsi3_write_aptpl_to_file() will call strlen() |
2084 | * on the passed buf to determine pr_aptpl_buf_len. | 2083 | * on the passed buf to determine pr_aptpl_buf_len. |
2085 | */ | 2084 | */ |
2086 | ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0); | 2085 | ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0); |
2087 | if (ret != 0) | 2086 | if (ret != 0) |
2088 | return ret; | 2087 | return ret; |
2089 | 2088 | ||
2090 | return ret; | 2089 | return ret; |
2091 | } | 2090 | } |
2092 | 2091 | ||
2093 | static int core_scsi3_emulate_pro_register( | 2092 | static int core_scsi3_emulate_pro_register( |
2094 | struct se_cmd *cmd, | 2093 | struct se_cmd *cmd, |
2095 | u64 res_key, | 2094 | u64 res_key, |
2096 | u64 sa_res_key, | 2095 | u64 sa_res_key, |
2097 | int aptpl, | 2096 | int aptpl, |
2098 | int all_tg_pt, | 2097 | int all_tg_pt, |
2099 | int spec_i_pt, | 2098 | int spec_i_pt, |
2100 | int ignore_key) | 2099 | int ignore_key) |
2101 | { | 2100 | { |
2102 | struct se_session *se_sess = cmd->se_sess; | 2101 | struct se_session *se_sess = cmd->se_sess; |
2103 | struct se_device *dev = cmd->se_dev; | 2102 | struct se_device *dev = cmd->se_dev; |
2104 | struct se_dev_entry *se_deve; | 2103 | struct se_dev_entry *se_deve; |
2105 | struct se_lun *se_lun = cmd->se_lun; | 2104 | struct se_lun *se_lun = cmd->se_lun; |
2106 | struct se_portal_group *se_tpg; | 2105 | struct se_portal_group *se_tpg; |
2107 | struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e; | 2106 | struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e; |
2108 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 2107 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
2109 | /* Used for APTPL metadata w/ UNREGISTER */ | 2108 | /* Used for APTPL metadata w/ UNREGISTER */ |
2110 | unsigned char *pr_aptpl_buf = NULL; | 2109 | unsigned char *pr_aptpl_buf = NULL; |
2111 | unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; | 2110 | unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; |
2112 | int pr_holder = 0, ret = 0, type; | 2111 | int pr_holder = 0, ret = 0, type; |
2113 | 2112 | ||
2114 | if (!se_sess || !se_lun) { | 2113 | if (!se_sess || !se_lun) { |
2115 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); | 2114 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); |
2116 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2115 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2117 | return -EINVAL; | 2116 | return -EINVAL; |
2118 | } | 2117 | } |
2119 | se_tpg = se_sess->se_tpg; | 2118 | se_tpg = se_sess->se_tpg; |
2120 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; | 2119 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; |
2121 | 2120 | ||
2122 | if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) { | 2121 | if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) { |
2123 | memset(&isid_buf[0], 0, PR_REG_ISID_LEN); | 2122 | memset(&isid_buf[0], 0, PR_REG_ISID_LEN); |
2124 | se_tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, &isid_buf[0], | 2123 | se_tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, &isid_buf[0], |
2125 | PR_REG_ISID_LEN); | 2124 | PR_REG_ISID_LEN); |
2126 | isid_ptr = &isid_buf[0]; | 2125 | isid_ptr = &isid_buf[0]; |
2127 | } | 2126 | } |
2128 | /* | 2127 | /* |
2129 | * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47 | 2128 | * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47 |
2130 | */ | 2129 | */ |
2131 | pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); | 2130 | pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); |
2132 | if (!pr_reg_e) { | 2131 | if (!pr_reg_e) { |
2133 | if (res_key) { | 2132 | if (res_key) { |
2134 | pr_warn("SPC-3 PR: Reservation Key non-zero" | 2133 | pr_warn("SPC-3 PR: Reservation Key non-zero" |
2135 | " for SA REGISTER, returning CONFLICT\n"); | 2134 | " for SA REGISTER, returning CONFLICT\n"); |
2136 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2135 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2137 | return -EINVAL; | 2136 | return -EINVAL; |
2138 | } | 2137 | } |
2139 | /* | 2138 | /* |
2140 | * Do nothing but return GOOD status. | 2139 | * Do nothing but return GOOD status. |
2141 | */ | 2140 | */ |
2142 | if (!sa_res_key) | 2141 | if (!sa_res_key) |
2143 | return 0; | 2142 | return 0; |
2144 | 2143 | ||
2145 | if (!spec_i_pt) { | 2144 | if (!spec_i_pt) { |
2146 | /* | 2145 | /* |
2147 | * Perform the Service Action REGISTER on the Initiator | 2146 | * Perform the Service Action REGISTER on the Initiator |
2148 | * Port Endpoint that the PRO was received from on the | 2147 | * Port Endpoint that the PRO was received from on the |
2149 | * Logical Unit of the SCSI device server. | 2148 | * Logical Unit of the SCSI device server. |
2150 | */ | 2149 | */ |
2151 | ret = core_scsi3_alloc_registration(cmd->se_dev, | 2150 | ret = core_scsi3_alloc_registration(cmd->se_dev, |
2152 | se_sess->se_node_acl, se_deve, isid_ptr, | 2151 | se_sess->se_node_acl, se_deve, isid_ptr, |
2153 | sa_res_key, all_tg_pt, aptpl, | 2152 | sa_res_key, all_tg_pt, aptpl, |
2154 | ignore_key, 0); | 2153 | ignore_key, 0); |
2155 | if (ret != 0) { | 2154 | if (ret != 0) { |
2156 | pr_err("Unable to allocate" | 2155 | pr_err("Unable to allocate" |
2157 | " struct t10_pr_registration\n"); | 2156 | " struct t10_pr_registration\n"); |
2158 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 2157 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
2159 | return -EINVAL; | 2158 | return -EINVAL; |
2160 | } | 2159 | } |
2161 | } else { | 2160 | } else { |
2162 | /* | 2161 | /* |
2163 | * Register both the Initiator port that received | 2162 | * Register both the Initiator port that received |
2164 | * PROUT SA REGISTER + SPEC_I_PT=1 and extract SCSI | 2163 | * PROUT SA REGISTER + SPEC_I_PT=1 and extract SCSI |
2165 | * TransportID from Parameter list and loop through | 2164 | * TransportID from Parameter list and loop through |
2166 | * fabric dependent parameter list while calling | 2165 | * fabric dependent parameter list while calling |
2167 | * logic from of core_scsi3_alloc_registration() for | 2166 | * logic from of core_scsi3_alloc_registration() for |
2168 | * each TransportID provided SCSI Initiator Port/Device | 2167 | * each TransportID provided SCSI Initiator Port/Device |
2169 | */ | 2168 | */ |
2170 | ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, | 2169 | ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, |
2171 | isid_ptr, sa_res_key, all_tg_pt, aptpl); | 2170 | isid_ptr, sa_res_key, all_tg_pt, aptpl); |
2172 | if (ret != 0) | 2171 | if (ret != 0) |
2173 | return ret; | 2172 | return ret; |
2174 | } | 2173 | } |
2175 | /* | 2174 | /* |
2176 | * Nothing left to do for the APTPL=0 case. | 2175 | * Nothing left to do for the APTPL=0 case. |
2177 | */ | 2176 | */ |
2178 | if (!aptpl) { | 2177 | if (!aptpl) { |
2179 | pr_tmpl->pr_aptpl_active = 0; | 2178 | pr_tmpl->pr_aptpl_active = 0; |
2180 | core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); | 2179 | core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); |
2181 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for" | 2180 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for" |
2182 | " REGISTER\n"); | 2181 | " REGISTER\n"); |
2183 | return 0; | 2182 | return 0; |
2184 | } | 2183 | } |
2185 | /* | 2184 | /* |
2186 | * Locate the newly allocated local I_T Nexus *pr_reg, and | 2185 | * Locate the newly allocated local I_T Nexus *pr_reg, and |
2187 | * update the APTPL metadata information using its | 2186 | * update the APTPL metadata information using its |
2188 | * preallocated *pr_reg->pr_aptpl_buf. | 2187 | * preallocated *pr_reg->pr_aptpl_buf. |
2189 | */ | 2188 | */ |
2190 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, | 2189 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, |
2191 | se_sess->se_node_acl, se_sess); | 2190 | se_sess->se_node_acl, se_sess); |
2192 | 2191 | ||
2193 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, | 2192 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, |
2194 | &pr_reg->pr_aptpl_buf[0], | 2193 | &pr_reg->pr_aptpl_buf[0], |
2195 | pr_tmpl->pr_aptpl_buf_len); | 2194 | pr_tmpl->pr_aptpl_buf_len); |
2196 | if (!ret) { | 2195 | if (!ret) { |
2197 | pr_tmpl->pr_aptpl_active = 1; | 2196 | pr_tmpl->pr_aptpl_active = 1; |
2198 | pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n"); | 2197 | pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n"); |
2199 | } | 2198 | } |
2200 | 2199 | ||
2201 | core_scsi3_put_pr_reg(pr_reg); | 2200 | core_scsi3_put_pr_reg(pr_reg); |
2202 | return ret; | 2201 | return ret; |
2203 | } else { | 2202 | } else { |
2204 | /* | 2203 | /* |
2205 | * Locate the existing *pr_reg via struct se_node_acl pointers | 2204 | * Locate the existing *pr_reg via struct se_node_acl pointers |
2206 | */ | 2205 | */ |
2207 | pr_reg = pr_reg_e; | 2206 | pr_reg = pr_reg_e; |
2208 | type = pr_reg->pr_res_type; | 2207 | type = pr_reg->pr_res_type; |
2209 | 2208 | ||
2210 | if (!ignore_key) { | 2209 | if (!ignore_key) { |
2211 | if (res_key != pr_reg->pr_res_key) { | 2210 | if (res_key != pr_reg->pr_res_key) { |
2212 | pr_err("SPC-3 PR REGISTER: Received" | 2211 | pr_err("SPC-3 PR REGISTER: Received" |
2213 | " res_key: 0x%016Lx does not match" | 2212 | " res_key: 0x%016Lx does not match" |
2214 | " existing SA REGISTER res_key:" | 2213 | " existing SA REGISTER res_key:" |
2215 | " 0x%016Lx\n", res_key, | 2214 | " 0x%016Lx\n", res_key, |
2216 | pr_reg->pr_res_key); | 2215 | pr_reg->pr_res_key); |
2217 | core_scsi3_put_pr_reg(pr_reg); | 2216 | core_scsi3_put_pr_reg(pr_reg); |
2218 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2217 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2219 | return -EINVAL; | 2218 | return -EINVAL; |
2220 | } | 2219 | } |
2221 | } | 2220 | } |
2222 | if (spec_i_pt) { | 2221 | if (spec_i_pt) { |
2223 | pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" | 2222 | pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" |
2224 | " set while sa_res_key=0\n"); | 2223 | " set while sa_res_key=0\n"); |
2225 | core_scsi3_put_pr_reg(pr_reg); | 2224 | core_scsi3_put_pr_reg(pr_reg); |
2226 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 2225 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
2227 | return -EINVAL; | 2226 | return -EINVAL; |
2228 | } | 2227 | } |
2229 | /* | 2228 | /* |
2230 | * An existing ALL_TG_PT=1 registration being released | 2229 | * An existing ALL_TG_PT=1 registration being released |
2231 | * must also set ALL_TG_PT=1 in the incoming PROUT. | 2230 | * must also set ALL_TG_PT=1 in the incoming PROUT. |
2232 | */ | 2231 | */ |
2233 | if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) { | 2232 | if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) { |
2234 | pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1" | 2233 | pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1" |
2235 | " registration exists, but ALL_TG_PT=1 bit not" | 2234 | " registration exists, but ALL_TG_PT=1 bit not" |
2236 | " present in received PROUT\n"); | 2235 | " present in received PROUT\n"); |
2237 | core_scsi3_put_pr_reg(pr_reg); | 2236 | core_scsi3_put_pr_reg(pr_reg); |
2238 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 2237 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
2239 | return -EINVAL; | 2238 | return -EINVAL; |
2240 | } | 2239 | } |
2241 | /* | 2240 | /* |
2242 | * Allocate APTPL metadata buffer used for UNREGISTER ops | 2241 | * Allocate APTPL metadata buffer used for UNREGISTER ops |
2243 | */ | 2242 | */ |
2244 | if (aptpl) { | 2243 | if (aptpl) { |
2245 | pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, | 2244 | pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, |
2246 | GFP_KERNEL); | 2245 | GFP_KERNEL); |
2247 | if (!pr_aptpl_buf) { | 2246 | if (!pr_aptpl_buf) { |
2248 | pr_err("Unable to allocate" | 2247 | pr_err("Unable to allocate" |
2249 | " pr_aptpl_buf\n"); | 2248 | " pr_aptpl_buf\n"); |
2250 | core_scsi3_put_pr_reg(pr_reg); | 2249 | core_scsi3_put_pr_reg(pr_reg); |
2251 | cmd->scsi_sense_reason = | 2250 | cmd->scsi_sense_reason = |
2252 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2251 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2253 | return -EINVAL; | 2252 | return -EINVAL; |
2254 | } | 2253 | } |
2255 | } | 2254 | } |
2256 | /* | 2255 | /* |
2257 | * sa_res_key=0 Unregister Reservation Key for registered I_T | 2256 | * sa_res_key=0 Unregister Reservation Key for registered I_T |
2258 | * Nexus sa_res_key=1 Change Reservation Key for registered I_T | 2257 | * Nexus sa_res_key=1 Change Reservation Key for registered I_T |
2259 | * Nexus. | 2258 | * Nexus. |
2260 | */ | 2259 | */ |
2261 | if (!sa_res_key) { | 2260 | if (!sa_res_key) { |
2262 | pr_holder = core_scsi3_check_implict_release( | 2261 | pr_holder = core_scsi3_check_implict_release( |
2263 | cmd->se_dev, pr_reg); | 2262 | cmd->se_dev, pr_reg); |
2264 | if (pr_holder < 0) { | 2263 | if (pr_holder < 0) { |
2265 | kfree(pr_aptpl_buf); | 2264 | kfree(pr_aptpl_buf); |
2266 | core_scsi3_put_pr_reg(pr_reg); | 2265 | core_scsi3_put_pr_reg(pr_reg); |
2267 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2266 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2268 | return -EINVAL; | 2267 | return -EINVAL; |
2269 | } | 2268 | } |
2270 | 2269 | ||
2271 | spin_lock(&pr_tmpl->registration_lock); | 2270 | spin_lock(&pr_tmpl->registration_lock); |
2272 | /* | 2271 | /* |
2273 | * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port | 2272 | * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port |
2274 | * and matching pr_res_key. | 2273 | * and matching pr_res_key. |
2275 | */ | 2274 | */ |
2276 | if (pr_reg->pr_reg_all_tg_pt) { | 2275 | if (pr_reg->pr_reg_all_tg_pt) { |
2277 | list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, | 2276 | list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, |
2278 | &pr_tmpl->registration_list, | 2277 | &pr_tmpl->registration_list, |
2279 | pr_reg_list) { | 2278 | pr_reg_list) { |
2280 | 2279 | ||
2281 | if (!pr_reg_p->pr_reg_all_tg_pt) | 2280 | if (!pr_reg_p->pr_reg_all_tg_pt) |
2282 | continue; | 2281 | continue; |
2283 | 2282 | ||
2284 | if (pr_reg_p->pr_res_key != res_key) | 2283 | if (pr_reg_p->pr_res_key != res_key) |
2285 | continue; | 2284 | continue; |
2286 | 2285 | ||
2287 | if (pr_reg == pr_reg_p) | 2286 | if (pr_reg == pr_reg_p) |
2288 | continue; | 2287 | continue; |
2289 | 2288 | ||
2290 | if (strcmp(pr_reg->pr_reg_nacl->initiatorname, | 2289 | if (strcmp(pr_reg->pr_reg_nacl->initiatorname, |
2291 | pr_reg_p->pr_reg_nacl->initiatorname)) | 2290 | pr_reg_p->pr_reg_nacl->initiatorname)) |
2292 | continue; | 2291 | continue; |
2293 | 2292 | ||
2294 | __core_scsi3_free_registration(dev, | 2293 | __core_scsi3_free_registration(dev, |
2295 | pr_reg_p, NULL, 0); | 2294 | pr_reg_p, NULL, 0); |
2296 | } | 2295 | } |
2297 | } | 2296 | } |
2298 | /* | 2297 | /* |
2299 | * Release the calling I_T Nexus registration now.. | 2298 | * Release the calling I_T Nexus registration now.. |
2300 | */ | 2299 | */ |
2301 | __core_scsi3_free_registration(cmd->se_dev, pr_reg, | 2300 | __core_scsi3_free_registration(cmd->se_dev, pr_reg, |
2302 | NULL, 1); | 2301 | NULL, 1); |
2303 | /* | 2302 | /* |
2304 | * From spc4r17, section 5.7.11.3 Unregistering | 2303 | * From spc4r17, section 5.7.11.3 Unregistering |
2305 | * | 2304 | * |
2306 | * If the persistent reservation is a registrants only | 2305 | * If the persistent reservation is a registrants only |
2307 | * type, the device server shall establish a unit | 2306 | * type, the device server shall establish a unit |
2308 | * attention condition for the initiator port associated | 2307 | * attention condition for the initiator port associated |
2309 | * with every registered I_T nexus except for the I_T | 2308 | * with every registered I_T nexus except for the I_T |
2310 | * nexus on which the PERSISTENT RESERVE OUT command was | 2309 | * nexus on which the PERSISTENT RESERVE OUT command was |
2311 | * received, with the additional sense code set to | 2310 | * received, with the additional sense code set to |
2312 | * RESERVATIONS RELEASED. | 2311 | * RESERVATIONS RELEASED. |
2313 | */ | 2312 | */ |
2314 | if (pr_holder && | 2313 | if (pr_holder && |
2315 | ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || | 2314 | ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || |
2316 | (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) { | 2315 | (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) { |
2317 | list_for_each_entry(pr_reg_p, | 2316 | list_for_each_entry(pr_reg_p, |
2318 | &pr_tmpl->registration_list, | 2317 | &pr_tmpl->registration_list, |
2319 | pr_reg_list) { | 2318 | pr_reg_list) { |
2320 | 2319 | ||
2321 | core_scsi3_ua_allocate( | 2320 | core_scsi3_ua_allocate( |
2322 | pr_reg_p->pr_reg_nacl, | 2321 | pr_reg_p->pr_reg_nacl, |
2323 | pr_reg_p->pr_res_mapped_lun, | 2322 | pr_reg_p->pr_res_mapped_lun, |
2324 | 0x2A, | 2323 | 0x2A, |
2325 | ASCQ_2AH_RESERVATIONS_RELEASED); | 2324 | ASCQ_2AH_RESERVATIONS_RELEASED); |
2326 | } | 2325 | } |
2327 | } | 2326 | } |
2328 | spin_unlock(&pr_tmpl->registration_lock); | 2327 | spin_unlock(&pr_tmpl->registration_lock); |
2329 | 2328 | ||
2330 | if (!aptpl) { | 2329 | if (!aptpl) { |
2331 | pr_tmpl->pr_aptpl_active = 0; | 2330 | pr_tmpl->pr_aptpl_active = 0; |
2332 | core_scsi3_update_and_write_aptpl(dev, NULL, 0); | 2331 | core_scsi3_update_and_write_aptpl(dev, NULL, 0); |
2333 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" | 2332 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" |
2334 | " for UNREGISTER\n"); | 2333 | " for UNREGISTER\n"); |
2335 | return 0; | 2334 | return 0; |
2336 | } | 2335 | } |
2337 | 2336 | ||
2338 | ret = core_scsi3_update_and_write_aptpl(dev, | 2337 | ret = core_scsi3_update_and_write_aptpl(dev, |
2339 | &pr_aptpl_buf[0], | 2338 | &pr_aptpl_buf[0], |
2340 | pr_tmpl->pr_aptpl_buf_len); | 2339 | pr_tmpl->pr_aptpl_buf_len); |
2341 | if (!ret) { | 2340 | if (!ret) { |
2342 | pr_tmpl->pr_aptpl_active = 1; | 2341 | pr_tmpl->pr_aptpl_active = 1; |
2343 | pr_debug("SPC-3 PR: Set APTPL Bit Activated" | 2342 | pr_debug("SPC-3 PR: Set APTPL Bit Activated" |
2344 | " for UNREGISTER\n"); | 2343 | " for UNREGISTER\n"); |
2345 | } | 2344 | } |
2346 | 2345 | ||
2347 | kfree(pr_aptpl_buf); | 2346 | kfree(pr_aptpl_buf); |
2348 | return ret; | 2347 | return ret; |
2349 | } else { | 2348 | } else { |
2350 | /* | 2349 | /* |
2351 | * Increment PRgeneration counter for struct se_device" | 2350 | * Increment PRgeneration counter for struct se_device" |
2352 | * upon a successful REGISTER, see spc4r17 section 6.3.2 | 2351 | * upon a successful REGISTER, see spc4r17 section 6.3.2 |
2353 | * READ_KEYS service action. | 2352 | * READ_KEYS service action. |
2354 | */ | 2353 | */ |
2355 | pr_reg->pr_res_generation = core_scsi3_pr_generation( | 2354 | pr_reg->pr_res_generation = core_scsi3_pr_generation( |
2356 | cmd->se_dev); | 2355 | cmd->se_dev); |
2357 | pr_reg->pr_res_key = sa_res_key; | 2356 | pr_reg->pr_res_key = sa_res_key; |
2358 | pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation" | 2357 | pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation" |
2359 | " Key for %s to: 0x%016Lx PRgeneration:" | 2358 | " Key for %s to: 0x%016Lx PRgeneration:" |
2360 | " 0x%08x\n", cmd->se_tfo->get_fabric_name(), | 2359 | " 0x%08x\n", cmd->se_tfo->get_fabric_name(), |
2361 | (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "", | 2360 | (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "", |
2362 | pr_reg->pr_reg_nacl->initiatorname, | 2361 | pr_reg->pr_reg_nacl->initiatorname, |
2363 | pr_reg->pr_res_key, pr_reg->pr_res_generation); | 2362 | pr_reg->pr_res_key, pr_reg->pr_res_generation); |
2364 | 2363 | ||
2365 | if (!aptpl) { | 2364 | if (!aptpl) { |
2366 | pr_tmpl->pr_aptpl_active = 0; | 2365 | pr_tmpl->pr_aptpl_active = 0; |
2367 | core_scsi3_update_and_write_aptpl(dev, NULL, 0); | 2366 | core_scsi3_update_and_write_aptpl(dev, NULL, 0); |
2368 | core_scsi3_put_pr_reg(pr_reg); | 2367 | core_scsi3_put_pr_reg(pr_reg); |
2369 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" | 2368 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" |
2370 | " for REGISTER\n"); | 2369 | " for REGISTER\n"); |
2371 | return 0; | 2370 | return 0; |
2372 | } | 2371 | } |
2373 | 2372 | ||
2374 | ret = core_scsi3_update_and_write_aptpl(dev, | 2373 | ret = core_scsi3_update_and_write_aptpl(dev, |
2375 | &pr_aptpl_buf[0], | 2374 | &pr_aptpl_buf[0], |
2376 | pr_tmpl->pr_aptpl_buf_len); | 2375 | pr_tmpl->pr_aptpl_buf_len); |
2377 | if (!ret) { | 2376 | if (!ret) { |
2378 | pr_tmpl->pr_aptpl_active = 1; | 2377 | pr_tmpl->pr_aptpl_active = 1; |
2379 | pr_debug("SPC-3 PR: Set APTPL Bit Activated" | 2378 | pr_debug("SPC-3 PR: Set APTPL Bit Activated" |
2380 | " for REGISTER\n"); | 2379 | " for REGISTER\n"); |
2381 | } | 2380 | } |
2382 | 2381 | ||
2383 | kfree(pr_aptpl_buf); | 2382 | kfree(pr_aptpl_buf); |
2384 | core_scsi3_put_pr_reg(pr_reg); | 2383 | core_scsi3_put_pr_reg(pr_reg); |
2385 | } | 2384 | } |
2386 | } | 2385 | } |
2387 | return 0; | 2386 | return 0; |
2388 | } | 2387 | } |
2389 | 2388 | ||
2390 | unsigned char *core_scsi3_pr_dump_type(int type) | 2389 | unsigned char *core_scsi3_pr_dump_type(int type) |
2391 | { | 2390 | { |
2392 | switch (type) { | 2391 | switch (type) { |
2393 | case PR_TYPE_WRITE_EXCLUSIVE: | 2392 | case PR_TYPE_WRITE_EXCLUSIVE: |
2394 | return "Write Exclusive Access"; | 2393 | return "Write Exclusive Access"; |
2395 | case PR_TYPE_EXCLUSIVE_ACCESS: | 2394 | case PR_TYPE_EXCLUSIVE_ACCESS: |
2396 | return "Exclusive Access"; | 2395 | return "Exclusive Access"; |
2397 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: | 2396 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: |
2398 | return "Write Exclusive Access, Registrants Only"; | 2397 | return "Write Exclusive Access, Registrants Only"; |
2399 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: | 2398 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: |
2400 | return "Exclusive Access, Registrants Only"; | 2399 | return "Exclusive Access, Registrants Only"; |
2401 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: | 2400 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: |
2402 | return "Write Exclusive Access, All Registrants"; | 2401 | return "Write Exclusive Access, All Registrants"; |
2403 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: | 2402 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: |
2404 | return "Exclusive Access, All Registrants"; | 2403 | return "Exclusive Access, All Registrants"; |
2405 | default: | 2404 | default: |
2406 | break; | 2405 | break; |
2407 | } | 2406 | } |
2408 | 2407 | ||
2409 | return "Unknown SPC-3 PR Type"; | 2408 | return "Unknown SPC-3 PR Type"; |
2410 | } | 2409 | } |
2411 | 2410 | ||
2412 | static int core_scsi3_pro_reserve( | 2411 | static int core_scsi3_pro_reserve( |
2413 | struct se_cmd *cmd, | 2412 | struct se_cmd *cmd, |
2414 | struct se_device *dev, | 2413 | struct se_device *dev, |
2415 | int type, | 2414 | int type, |
2416 | int scope, | 2415 | int scope, |
2417 | u64 res_key) | 2416 | u64 res_key) |
2418 | { | 2417 | { |
2419 | struct se_session *se_sess = cmd->se_sess; | 2418 | struct se_session *se_sess = cmd->se_sess; |
2420 | struct se_dev_entry *se_deve; | 2419 | struct se_dev_entry *se_deve; |
2421 | struct se_lun *se_lun = cmd->se_lun; | 2420 | struct se_lun *se_lun = cmd->se_lun; |
2422 | struct se_portal_group *se_tpg; | 2421 | struct se_portal_group *se_tpg; |
2423 | struct t10_pr_registration *pr_reg, *pr_res_holder; | 2422 | struct t10_pr_registration *pr_reg, *pr_res_holder; |
2424 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 2423 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
2425 | char i_buf[PR_REG_ISID_ID_LEN]; | 2424 | char i_buf[PR_REG_ISID_ID_LEN]; |
2426 | int ret, prf_isid; | 2425 | int ret, prf_isid; |
2427 | 2426 | ||
2428 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 2427 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
2429 | 2428 | ||
2430 | if (!se_sess || !se_lun) { | 2429 | if (!se_sess || !se_lun) { |
2431 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); | 2430 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); |
2432 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2431 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2433 | return -EINVAL; | 2432 | return -EINVAL; |
2434 | } | 2433 | } |
2435 | se_tpg = se_sess->se_tpg; | 2434 | se_tpg = se_sess->se_tpg; |
2436 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; | 2435 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; |
2437 | /* | 2436 | /* |
2438 | * Locate the existing *pr_reg via struct se_node_acl pointers | 2437 | * Locate the existing *pr_reg via struct se_node_acl pointers |
2439 | */ | 2438 | */ |
2440 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, | 2439 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, |
2441 | se_sess); | 2440 | se_sess); |
2442 | if (!pr_reg) { | 2441 | if (!pr_reg) { |
2443 | pr_err("SPC-3 PR: Unable to locate" | 2442 | pr_err("SPC-3 PR: Unable to locate" |
2444 | " PR_REGISTERED *pr_reg for RESERVE\n"); | 2443 | " PR_REGISTERED *pr_reg for RESERVE\n"); |
2445 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2444 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2446 | return -EINVAL; | 2445 | return -EINVAL; |
2447 | } | 2446 | } |
2448 | /* | 2447 | /* |
2449 | * From spc4r17 Section 5.7.9: Reserving: | 2448 | * From spc4r17 Section 5.7.9: Reserving: |
2450 | * | 2449 | * |
2451 | * An application client creates a persistent reservation by issuing | 2450 | * An application client creates a persistent reservation by issuing |
2452 | * a PERSISTENT RESERVE OUT command with RESERVE service action through | 2451 | * a PERSISTENT RESERVE OUT command with RESERVE service action through |
2453 | * a registered I_T nexus with the following parameters: | 2452 | * a registered I_T nexus with the following parameters: |
2454 | * a) RESERVATION KEY set to the value of the reservation key that is | 2453 | * a) RESERVATION KEY set to the value of the reservation key that is |
2455 | * registered with the logical unit for the I_T nexus; and | 2454 | * registered with the logical unit for the I_T nexus; and |
2456 | */ | 2455 | */ |
2457 | if (res_key != pr_reg->pr_res_key) { | 2456 | if (res_key != pr_reg->pr_res_key) { |
2458 | pr_err("SPC-3 PR RESERVE: Received res_key: 0x%016Lx" | 2457 | pr_err("SPC-3 PR RESERVE: Received res_key: 0x%016Lx" |
2459 | " does not match existing SA REGISTER res_key:" | 2458 | " does not match existing SA REGISTER res_key:" |
2460 | " 0x%016Lx\n", res_key, pr_reg->pr_res_key); | 2459 | " 0x%016Lx\n", res_key, pr_reg->pr_res_key); |
2461 | core_scsi3_put_pr_reg(pr_reg); | 2460 | core_scsi3_put_pr_reg(pr_reg); |
2462 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2461 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2463 | return -EINVAL; | 2462 | return -EINVAL; |
2464 | } | 2463 | } |
2465 | /* | 2464 | /* |
2466 | * From spc4r17 Section 5.7.9: Reserving: | 2465 | * From spc4r17 Section 5.7.9: Reserving: |
2467 | * | 2466 | * |
2468 | * From above: | 2467 | * From above: |
2469 | * b) TYPE field and SCOPE field set to the persistent reservation | 2468 | * b) TYPE field and SCOPE field set to the persistent reservation |
2470 | * being created. | 2469 | * being created. |
2471 | * | 2470 | * |
2472 | * Only one persistent reservation is allowed at a time per logical unit | 2471 | * Only one persistent reservation is allowed at a time per logical unit |
2473 | * and that persistent reservation has a scope of LU_SCOPE. | 2472 | * and that persistent reservation has a scope of LU_SCOPE. |
2474 | */ | 2473 | */ |
2475 | if (scope != PR_SCOPE_LU_SCOPE) { | 2474 | if (scope != PR_SCOPE_LU_SCOPE) { |
2476 | pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); | 2475 | pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); |
2477 | core_scsi3_put_pr_reg(pr_reg); | 2476 | core_scsi3_put_pr_reg(pr_reg); |
2478 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 2477 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
2479 | return -EINVAL; | 2478 | return -EINVAL; |
2480 | } | 2479 | } |
2481 | /* | 2480 | /* |
2482 | * See if we have an existing PR reservation holder pointer at | 2481 | * See if we have an existing PR reservation holder pointer at |
2483 | * struct se_device->dev_pr_res_holder in the form struct t10_pr_registration | 2482 | * struct se_device->dev_pr_res_holder in the form struct t10_pr_registration |
2484 | * *pr_res_holder. | 2483 | * *pr_res_holder. |
2485 | */ | 2484 | */ |
2486 | spin_lock(&dev->dev_reservation_lock); | 2485 | spin_lock(&dev->dev_reservation_lock); |
2487 | pr_res_holder = dev->dev_pr_res_holder; | 2486 | pr_res_holder = dev->dev_pr_res_holder; |
2488 | if ((pr_res_holder)) { | 2487 | if ((pr_res_holder)) { |
2489 | /* | 2488 | /* |
2490 | * From spc4r17 Section 5.7.9: Reserving: | 2489 | * From spc4r17 Section 5.7.9: Reserving: |
2491 | * | 2490 | * |
2492 | * If the device server receives a PERSISTENT RESERVE OUT | 2491 | * If the device server receives a PERSISTENT RESERVE OUT |
2493 | * command from an I_T nexus other than a persistent reservation | 2492 | * command from an I_T nexus other than a persistent reservation |
2494 | * holder (see 5.7.10) that attempts to create a persistent | 2493 | * holder (see 5.7.10) that attempts to create a persistent |
2495 | * reservation when a persistent reservation already exists for | 2494 | * reservation when a persistent reservation already exists for |
2496 | * the logical unit, then the command shall be completed with | 2495 | * the logical unit, then the command shall be completed with |
2497 | * RESERVATION CONFLICT status. | 2496 | * RESERVATION CONFLICT status. |
2498 | */ | 2497 | */ |
2499 | if (pr_res_holder != pr_reg) { | 2498 | if (pr_res_holder != pr_reg) { |
2500 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 2499 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
2501 | pr_err("SPC-3 PR: Attempted RESERVE from" | 2500 | pr_err("SPC-3 PR: Attempted RESERVE from" |
2502 | " [%s]: %s while reservation already held by" | 2501 | " [%s]: %s while reservation already held by" |
2503 | " [%s]: %s, returning RESERVATION_CONFLICT\n", | 2502 | " [%s]: %s, returning RESERVATION_CONFLICT\n", |
2504 | cmd->se_tfo->get_fabric_name(), | 2503 | cmd->se_tfo->get_fabric_name(), |
2505 | se_sess->se_node_acl->initiatorname, | 2504 | se_sess->se_node_acl->initiatorname, |
2506 | pr_res_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), | 2505 | pr_res_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
2507 | pr_res_holder->pr_reg_nacl->initiatorname); | 2506 | pr_res_holder->pr_reg_nacl->initiatorname); |
2508 | 2507 | ||
2509 | spin_unlock(&dev->dev_reservation_lock); | 2508 | spin_unlock(&dev->dev_reservation_lock); |
2510 | core_scsi3_put_pr_reg(pr_reg); | 2509 | core_scsi3_put_pr_reg(pr_reg); |
2511 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2510 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2512 | return -EINVAL; | 2511 | return -EINVAL; |
2513 | } | 2512 | } |
2514 | /* | 2513 | /* |
2515 | * From spc4r17 Section 5.7.9: Reserving: | 2514 | * From spc4r17 Section 5.7.9: Reserving: |
2516 | * | 2515 | * |
2517 | * If a persistent reservation holder attempts to modify the | 2516 | * If a persistent reservation holder attempts to modify the |
2518 | * type or scope of an existing persistent reservation, the | 2517 | * type or scope of an existing persistent reservation, the |
2519 | * command shall be completed with RESERVATION CONFLICT status. | 2518 | * command shall be completed with RESERVATION CONFLICT status. |
2520 | */ | 2519 | */ |
2521 | if ((pr_res_holder->pr_res_type != type) || | 2520 | if ((pr_res_holder->pr_res_type != type) || |
2522 | (pr_res_holder->pr_res_scope != scope)) { | 2521 | (pr_res_holder->pr_res_scope != scope)) { |
2523 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 2522 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
2524 | pr_err("SPC-3 PR: Attempted RESERVE from" | 2523 | pr_err("SPC-3 PR: Attempted RESERVE from" |
2525 | " [%s]: %s trying to change TYPE and/or SCOPE," | 2524 | " [%s]: %s trying to change TYPE and/or SCOPE," |
2526 | " while reservation already held by [%s]: %s," | 2525 | " while reservation already held by [%s]: %s," |
2527 | " returning RESERVATION_CONFLICT\n", | 2526 | " returning RESERVATION_CONFLICT\n", |
2528 | cmd->se_tfo->get_fabric_name(), | 2527 | cmd->se_tfo->get_fabric_name(), |
2529 | se_sess->se_node_acl->initiatorname, | 2528 | se_sess->se_node_acl->initiatorname, |
2530 | pr_res_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), | 2529 | pr_res_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
2531 | pr_res_holder->pr_reg_nacl->initiatorname); | 2530 | pr_res_holder->pr_reg_nacl->initiatorname); |
2532 | 2531 | ||
2533 | spin_unlock(&dev->dev_reservation_lock); | 2532 | spin_unlock(&dev->dev_reservation_lock); |
2534 | core_scsi3_put_pr_reg(pr_reg); | 2533 | core_scsi3_put_pr_reg(pr_reg); |
2535 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2534 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2536 | return -EINVAL; | 2535 | return -EINVAL; |
2537 | } | 2536 | } |
2538 | /* | 2537 | /* |
2539 | * From spc4r17 Section 5.7.9: Reserving: | 2538 | * From spc4r17 Section 5.7.9: Reserving: |
2540 | * | 2539 | * |
2541 | * If the device server receives a PERSISTENT RESERVE OUT | 2540 | * If the device server receives a PERSISTENT RESERVE OUT |
2542 | * command with RESERVE service action where the TYPE field and | 2541 | * command with RESERVE service action where the TYPE field and |
2543 | * the SCOPE field contain the same values as the existing type | 2542 | * the SCOPE field contain the same values as the existing type |
2544 | * and scope from a persistent reservation holder, it shall not | 2543 | * and scope from a persistent reservation holder, it shall not |
2545 | * make any change to the existing persistent reservation and | 2544 | * make any change to the existing persistent reservation and |
2546 | * shall completethe command with GOOD status. | 2545 | * shall completethe command with GOOD status. |
2547 | */ | 2546 | */ |
2548 | spin_unlock(&dev->dev_reservation_lock); | 2547 | spin_unlock(&dev->dev_reservation_lock); |
2549 | core_scsi3_put_pr_reg(pr_reg); | 2548 | core_scsi3_put_pr_reg(pr_reg); |
2550 | return 0; | 2549 | return 0; |
2551 | } | 2550 | } |
2552 | /* | 2551 | /* |
2553 | * Otherwise, our *pr_reg becomes the PR reservation holder for said | 2552 | * Otherwise, our *pr_reg becomes the PR reservation holder for said |
2554 | * TYPE/SCOPE. Also set the received scope and type in *pr_reg. | 2553 | * TYPE/SCOPE. Also set the received scope and type in *pr_reg. |
2555 | */ | 2554 | */ |
2556 | pr_reg->pr_res_scope = scope; | 2555 | pr_reg->pr_res_scope = scope; |
2557 | pr_reg->pr_res_type = type; | 2556 | pr_reg->pr_res_type = type; |
2558 | pr_reg->pr_res_holder = 1; | 2557 | pr_reg->pr_res_holder = 1; |
2559 | dev->dev_pr_res_holder = pr_reg; | 2558 | dev->dev_pr_res_holder = pr_reg; |
2560 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 2559 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
2561 | PR_REG_ISID_ID_LEN); | 2560 | PR_REG_ISID_ID_LEN); |
2562 | 2561 | ||
2563 | pr_debug("SPC-3 PR [%s] Service Action: RESERVE created new" | 2562 | pr_debug("SPC-3 PR [%s] Service Action: RESERVE created new" |
2564 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", | 2563 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", |
2565 | cmd->se_tfo->get_fabric_name(), core_scsi3_pr_dump_type(type), | 2564 | cmd->se_tfo->get_fabric_name(), core_scsi3_pr_dump_type(type), |
2566 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); | 2565 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); |
2567 | pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n", | 2566 | pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n", |
2568 | cmd->se_tfo->get_fabric_name(), | 2567 | cmd->se_tfo->get_fabric_name(), |
2569 | se_sess->se_node_acl->initiatorname, | 2568 | se_sess->se_node_acl->initiatorname, |
2570 | (prf_isid) ? &i_buf[0] : ""); | 2569 | (prf_isid) ? &i_buf[0] : ""); |
2571 | spin_unlock(&dev->dev_reservation_lock); | 2570 | spin_unlock(&dev->dev_reservation_lock); |
2572 | 2571 | ||
2573 | if (pr_tmpl->pr_aptpl_active) { | 2572 | if (pr_tmpl->pr_aptpl_active) { |
2574 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, | 2573 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, |
2575 | &pr_reg->pr_aptpl_buf[0], | 2574 | &pr_reg->pr_aptpl_buf[0], |
2576 | pr_tmpl->pr_aptpl_buf_len); | 2575 | pr_tmpl->pr_aptpl_buf_len); |
2577 | if (!ret) | 2576 | if (!ret) |
2578 | pr_debug("SPC-3 PR: Updated APTPL metadata" | 2577 | pr_debug("SPC-3 PR: Updated APTPL metadata" |
2579 | " for RESERVE\n"); | 2578 | " for RESERVE\n"); |
2580 | } | 2579 | } |
2581 | 2580 | ||
2582 | core_scsi3_put_pr_reg(pr_reg); | 2581 | core_scsi3_put_pr_reg(pr_reg); |
2583 | return 0; | 2582 | return 0; |
2584 | } | 2583 | } |
2585 | 2584 | ||
2586 | static int core_scsi3_emulate_pro_reserve( | 2585 | static int core_scsi3_emulate_pro_reserve( |
2587 | struct se_cmd *cmd, | 2586 | struct se_cmd *cmd, |
2588 | int type, | 2587 | int type, |
2589 | int scope, | 2588 | int scope, |
2590 | u64 res_key) | 2589 | u64 res_key) |
2591 | { | 2590 | { |
2592 | struct se_device *dev = cmd->se_dev; | 2591 | struct se_device *dev = cmd->se_dev; |
2593 | int ret = 0; | 2592 | int ret = 0; |
2594 | 2593 | ||
2595 | switch (type) { | 2594 | switch (type) { |
2596 | case PR_TYPE_WRITE_EXCLUSIVE: | 2595 | case PR_TYPE_WRITE_EXCLUSIVE: |
2597 | case PR_TYPE_EXCLUSIVE_ACCESS: | 2596 | case PR_TYPE_EXCLUSIVE_ACCESS: |
2598 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: | 2597 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: |
2599 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: | 2598 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: |
2600 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: | 2599 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: |
2601 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: | 2600 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: |
2602 | ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key); | 2601 | ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key); |
2603 | break; | 2602 | break; |
2604 | default: | 2603 | default: |
2605 | pr_err("SPC-3 PR: Unknown Service Action RESERVE Type:" | 2604 | pr_err("SPC-3 PR: Unknown Service Action RESERVE Type:" |
2606 | " 0x%02x\n", type); | 2605 | " 0x%02x\n", type); |
2607 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 2606 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
2608 | return -EINVAL; | 2607 | return -EINVAL; |
2609 | } | 2608 | } |
2610 | 2609 | ||
2611 | return ret; | 2610 | return ret; |
2612 | } | 2611 | } |
2613 | 2612 | ||
2614 | /* | 2613 | /* |
2615 | * Called with struct se_device->dev_reservation_lock held. | 2614 | * Called with struct se_device->dev_reservation_lock held. |
2616 | */ | 2615 | */ |
2617 | static void __core_scsi3_complete_pro_release( | 2616 | static void __core_scsi3_complete_pro_release( |
2618 | struct se_device *dev, | 2617 | struct se_device *dev, |
2619 | struct se_node_acl *se_nacl, | 2618 | struct se_node_acl *se_nacl, |
2620 | struct t10_pr_registration *pr_reg, | 2619 | struct t10_pr_registration *pr_reg, |
2621 | int explict) | 2620 | int explict) |
2622 | { | 2621 | { |
2623 | struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; | 2622 | struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; |
2624 | char i_buf[PR_REG_ISID_ID_LEN]; | 2623 | char i_buf[PR_REG_ISID_ID_LEN]; |
2625 | int prf_isid; | 2624 | int prf_isid; |
2626 | 2625 | ||
2627 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 2626 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
2628 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 2627 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
2629 | PR_REG_ISID_ID_LEN); | 2628 | PR_REG_ISID_ID_LEN); |
2630 | /* | 2629 | /* |
2631 | * Go ahead and release the current PR reservation holder. | 2630 | * Go ahead and release the current PR reservation holder. |
2632 | */ | 2631 | */ |
2633 | dev->dev_pr_res_holder = NULL; | 2632 | dev->dev_pr_res_holder = NULL; |
2634 | 2633 | ||
2635 | pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared" | 2634 | pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared" |
2636 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", | 2635 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", |
2637 | tfo->get_fabric_name(), (explict) ? "explict" : "implict", | 2636 | tfo->get_fabric_name(), (explict) ? "explict" : "implict", |
2638 | core_scsi3_pr_dump_type(pr_reg->pr_res_type), | 2637 | core_scsi3_pr_dump_type(pr_reg->pr_res_type), |
2639 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); | 2638 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); |
2640 | pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n", | 2639 | pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n", |
2641 | tfo->get_fabric_name(), se_nacl->initiatorname, | 2640 | tfo->get_fabric_name(), se_nacl->initiatorname, |
2642 | (prf_isid) ? &i_buf[0] : ""); | 2641 | (prf_isid) ? &i_buf[0] : ""); |
2643 | /* | 2642 | /* |
2644 | * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE | 2643 | * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE |
2645 | */ | 2644 | */ |
2646 | pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0; | 2645 | pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0; |
2647 | } | 2646 | } |
2648 | 2647 | ||
2649 | static int core_scsi3_emulate_pro_release( | 2648 | static int core_scsi3_emulate_pro_release( |
2650 | struct se_cmd *cmd, | 2649 | struct se_cmd *cmd, |
2651 | int type, | 2650 | int type, |
2652 | int scope, | 2651 | int scope, |
2653 | u64 res_key) | 2652 | u64 res_key) |
2654 | { | 2653 | { |
2655 | struct se_device *dev = cmd->se_dev; | 2654 | struct se_device *dev = cmd->se_dev; |
2656 | struct se_session *se_sess = cmd->se_sess; | 2655 | struct se_session *se_sess = cmd->se_sess; |
2657 | struct se_lun *se_lun = cmd->se_lun; | 2656 | struct se_lun *se_lun = cmd->se_lun; |
2658 | struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder; | 2657 | struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder; |
2659 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 2658 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
2660 | int ret, all_reg = 0; | 2659 | int ret, all_reg = 0; |
2661 | 2660 | ||
2662 | if (!se_sess || !se_lun) { | 2661 | if (!se_sess || !se_lun) { |
2663 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); | 2662 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); |
2664 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2663 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2665 | return -EINVAL; | 2664 | return -EINVAL; |
2666 | } | 2665 | } |
2667 | /* | 2666 | /* |
2668 | * Locate the existing *pr_reg via struct se_node_acl pointers | 2667 | * Locate the existing *pr_reg via struct se_node_acl pointers |
2669 | */ | 2668 | */ |
2670 | pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); | 2669 | pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); |
2671 | if (!pr_reg) { | 2670 | if (!pr_reg) { |
2672 | pr_err("SPC-3 PR: Unable to locate" | 2671 | pr_err("SPC-3 PR: Unable to locate" |
2673 | " PR_REGISTERED *pr_reg for RELEASE\n"); | 2672 | " PR_REGISTERED *pr_reg for RELEASE\n"); |
2674 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2673 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2675 | return -EINVAL; | 2674 | return -EINVAL; |
2676 | } | 2675 | } |
2677 | /* | 2676 | /* |
2678 | * From spc4r17 Section 5.7.11.2 Releasing: | 2677 | * From spc4r17 Section 5.7.11.2 Releasing: |
2679 | * | 2678 | * |
2680 | * If there is no persistent reservation or in response to a persistent | 2679 | * If there is no persistent reservation or in response to a persistent |
2681 | * reservation release request from a registered I_T nexus that is not a | 2680 | * reservation release request from a registered I_T nexus that is not a |
2682 | * persistent reservation holder (see 5.7.10), the device server shall | 2681 | * persistent reservation holder (see 5.7.10), the device server shall |
2683 | * do the following: | 2682 | * do the following: |
2684 | * | 2683 | * |
2685 | * a) Not release the persistent reservation, if any; | 2684 | * a) Not release the persistent reservation, if any; |
2686 | * b) Not remove any registrations; and | 2685 | * b) Not remove any registrations; and |
2687 | * c) Complete the command with GOOD status. | 2686 | * c) Complete the command with GOOD status. |
2688 | */ | 2687 | */ |
2689 | spin_lock(&dev->dev_reservation_lock); | 2688 | spin_lock(&dev->dev_reservation_lock); |
2690 | pr_res_holder = dev->dev_pr_res_holder; | 2689 | pr_res_holder = dev->dev_pr_res_holder; |
2691 | if (!pr_res_holder) { | 2690 | if (!pr_res_holder) { |
2692 | /* | 2691 | /* |
2693 | * No persistent reservation, return GOOD status. | 2692 | * No persistent reservation, return GOOD status. |
2694 | */ | 2693 | */ |
2695 | spin_unlock(&dev->dev_reservation_lock); | 2694 | spin_unlock(&dev->dev_reservation_lock); |
2696 | core_scsi3_put_pr_reg(pr_reg); | 2695 | core_scsi3_put_pr_reg(pr_reg); |
2697 | return 0; | 2696 | return 0; |
2698 | } | 2697 | } |
2699 | if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | 2698 | if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || |
2700 | (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) | 2699 | (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) |
2701 | all_reg = 1; | 2700 | all_reg = 1; |
2702 | 2701 | ||
2703 | if ((all_reg == 0) && (pr_res_holder != pr_reg)) { | 2702 | if ((all_reg == 0) && (pr_res_holder != pr_reg)) { |
2704 | /* | 2703 | /* |
2705 | * Non 'All Registrants' PR Type cases.. | 2704 | * Non 'All Registrants' PR Type cases.. |
2706 | * Release request from a registered I_T nexus that is not a | 2705 | * Release request from a registered I_T nexus that is not a |
2707 | * persistent reservation holder. return GOOD status. | 2706 | * persistent reservation holder. return GOOD status. |
2708 | */ | 2707 | */ |
2709 | spin_unlock(&dev->dev_reservation_lock); | 2708 | spin_unlock(&dev->dev_reservation_lock); |
2710 | core_scsi3_put_pr_reg(pr_reg); | 2709 | core_scsi3_put_pr_reg(pr_reg); |
2711 | return 0; | 2710 | return 0; |
2712 | } | 2711 | } |
2713 | /* | 2712 | /* |
2714 | * From spc4r17 Section 5.7.11.2 Releasing: | 2713 | * From spc4r17 Section 5.7.11.2 Releasing: |
2715 | * | 2714 | * |
2716 | * Only the persistent reservation holder (see 5.7.10) is allowed to | 2715 | * Only the persistent reservation holder (see 5.7.10) is allowed to |
2717 | * release a persistent reservation. | 2716 | * release a persistent reservation. |
2718 | * | 2717 | * |
2719 | * An application client releases the persistent reservation by issuing | 2718 | * An application client releases the persistent reservation by issuing |
2720 | * a PERSISTENT RESERVE OUT command with RELEASE service action through | 2719 | * a PERSISTENT RESERVE OUT command with RELEASE service action through |
2721 | * an I_T nexus that is a persistent reservation holder with the | 2720 | * an I_T nexus that is a persistent reservation holder with the |
2722 | * following parameters: | 2721 | * following parameters: |
2723 | * | 2722 | * |
2724 | * a) RESERVATION KEY field set to the value of the reservation key | 2723 | * a) RESERVATION KEY field set to the value of the reservation key |
2725 | * that is registered with the logical unit for the I_T nexus; | 2724 | * that is registered with the logical unit for the I_T nexus; |
2726 | */ | 2725 | */ |
2727 | if (res_key != pr_reg->pr_res_key) { | 2726 | if (res_key != pr_reg->pr_res_key) { |
2728 | pr_err("SPC-3 PR RELEASE: Received res_key: 0x%016Lx" | 2727 | pr_err("SPC-3 PR RELEASE: Received res_key: 0x%016Lx" |
2729 | " does not match existing SA REGISTER res_key:" | 2728 | " does not match existing SA REGISTER res_key:" |
2730 | " 0x%016Lx\n", res_key, pr_reg->pr_res_key); | 2729 | " 0x%016Lx\n", res_key, pr_reg->pr_res_key); |
2731 | spin_unlock(&dev->dev_reservation_lock); | 2730 | spin_unlock(&dev->dev_reservation_lock); |
2732 | core_scsi3_put_pr_reg(pr_reg); | 2731 | core_scsi3_put_pr_reg(pr_reg); |
2733 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2732 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2734 | return -EINVAL; | 2733 | return -EINVAL; |
2735 | } | 2734 | } |
2736 | /* | 2735 | /* |
2737 | * From spc4r17 Section 5.7.11.2 Releasing and above: | 2736 | * From spc4r17 Section 5.7.11.2 Releasing and above: |
2738 | * | 2737 | * |
2739 | * b) TYPE field and SCOPE field set to match the persistent | 2738 | * b) TYPE field and SCOPE field set to match the persistent |
2740 | * reservation being released. | 2739 | * reservation being released. |
2741 | */ | 2740 | */ |
2742 | if ((pr_res_holder->pr_res_type != type) || | 2741 | if ((pr_res_holder->pr_res_type != type) || |
2743 | (pr_res_holder->pr_res_scope != scope)) { | 2742 | (pr_res_holder->pr_res_scope != scope)) { |
2744 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 2743 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
2745 | pr_err("SPC-3 PR RELEASE: Attempted to release" | 2744 | pr_err("SPC-3 PR RELEASE: Attempted to release" |
2746 | " reservation from [%s]: %s with different TYPE " | 2745 | " reservation from [%s]: %s with different TYPE " |
2747 | "and/or SCOPE while reservation already held by" | 2746 | "and/or SCOPE while reservation already held by" |
2748 | " [%s]: %s, returning RESERVATION_CONFLICT\n", | 2747 | " [%s]: %s, returning RESERVATION_CONFLICT\n", |
2749 | cmd->se_tfo->get_fabric_name(), | 2748 | cmd->se_tfo->get_fabric_name(), |
2750 | se_sess->se_node_acl->initiatorname, | 2749 | se_sess->se_node_acl->initiatorname, |
2751 | pr_res_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), | 2750 | pr_res_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), |
2752 | pr_res_holder->pr_reg_nacl->initiatorname); | 2751 | pr_res_holder->pr_reg_nacl->initiatorname); |
2753 | 2752 | ||
2754 | spin_unlock(&dev->dev_reservation_lock); | 2753 | spin_unlock(&dev->dev_reservation_lock); |
2755 | core_scsi3_put_pr_reg(pr_reg); | 2754 | core_scsi3_put_pr_reg(pr_reg); |
2756 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2755 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2757 | return -EINVAL; | 2756 | return -EINVAL; |
2758 | } | 2757 | } |
2759 | /* | 2758 | /* |
2760 | * In response to a persistent reservation release request from the | 2759 | * In response to a persistent reservation release request from the |
2761 | * persistent reservation holder the device server shall perform a | 2760 | * persistent reservation holder the device server shall perform a |
2762 | * release by doing the following as an uninterrupted series of actions: | 2761 | * release by doing the following as an uninterrupted series of actions: |
2763 | * a) Release the persistent reservation; | 2762 | * a) Release the persistent reservation; |
2764 | * b) Not remove any registration(s); | 2763 | * b) Not remove any registration(s); |
2765 | * c) If the released persistent reservation is a registrants only type | 2764 | * c) If the released persistent reservation is a registrants only type |
2766 | * or all registrants type persistent reservation, | 2765 | * or all registrants type persistent reservation, |
2767 | * the device server shall establish a unit attention condition for | 2766 | * the device server shall establish a unit attention condition for |
2768 | * the initiator port associated with every regis- | 2767 | * the initiator port associated with every regis- |
2769 | * tered I_T nexus other than I_T nexus on which the PERSISTENT | 2768 | * tered I_T nexus other than I_T nexus on which the PERSISTENT |
2770 | * RESERVE OUT command with RELEASE service action was received, | 2769 | * RESERVE OUT command with RELEASE service action was received, |
2771 | * with the additional sense code set to RESERVATIONS RELEASED; and | 2770 | * with the additional sense code set to RESERVATIONS RELEASED; and |
2772 | * d) If the persistent reservation is of any other type, the device | 2771 | * d) If the persistent reservation is of any other type, the device |
2773 | * server shall not establish a unit attention condition. | 2772 | * server shall not establish a unit attention condition. |
2774 | */ | 2773 | */ |
2775 | __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl, | 2774 | __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl, |
2776 | pr_reg, 1); | 2775 | pr_reg, 1); |
2777 | 2776 | ||
2778 | spin_unlock(&dev->dev_reservation_lock); | 2777 | spin_unlock(&dev->dev_reservation_lock); |
2779 | 2778 | ||
2780 | if ((type != PR_TYPE_WRITE_EXCLUSIVE_REGONLY) && | 2779 | if ((type != PR_TYPE_WRITE_EXCLUSIVE_REGONLY) && |
2781 | (type != PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) && | 2780 | (type != PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) && |
2782 | (type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) && | 2781 | (type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) && |
2783 | (type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { | 2782 | (type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { |
2784 | /* | 2783 | /* |
2785 | * If no UNIT ATTENTION conditions will be established for | 2784 | * If no UNIT ATTENTION conditions will be established for |
2786 | * PR_TYPE_WRITE_EXCLUSIVE or PR_TYPE_EXCLUSIVE_ACCESS | 2785 | * PR_TYPE_WRITE_EXCLUSIVE or PR_TYPE_EXCLUSIVE_ACCESS |
2787 | * go ahead and check for APTPL=1 update+write below | 2786 | * go ahead and check for APTPL=1 update+write below |
2788 | */ | 2787 | */ |
2789 | goto write_aptpl; | 2788 | goto write_aptpl; |
2790 | } | 2789 | } |
2791 | 2790 | ||
2792 | spin_lock(&pr_tmpl->registration_lock); | 2791 | spin_lock(&pr_tmpl->registration_lock); |
2793 | list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list, | 2792 | list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list, |
2794 | pr_reg_list) { | 2793 | pr_reg_list) { |
2795 | /* | 2794 | /* |
2796 | * Do not establish a UNIT ATTENTION condition | 2795 | * Do not establish a UNIT ATTENTION condition |
2797 | * for the calling I_T Nexus | 2796 | * for the calling I_T Nexus |
2798 | */ | 2797 | */ |
2799 | if (pr_reg_p == pr_reg) | 2798 | if (pr_reg_p == pr_reg) |
2800 | continue; | 2799 | continue; |
2801 | 2800 | ||
2802 | core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl, | 2801 | core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl, |
2803 | pr_reg_p->pr_res_mapped_lun, | 2802 | pr_reg_p->pr_res_mapped_lun, |
2804 | 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED); | 2803 | 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED); |
2805 | } | 2804 | } |
2806 | spin_unlock(&pr_tmpl->registration_lock); | 2805 | spin_unlock(&pr_tmpl->registration_lock); |
2807 | 2806 | ||
2808 | write_aptpl: | 2807 | write_aptpl: |
2809 | if (pr_tmpl->pr_aptpl_active) { | 2808 | if (pr_tmpl->pr_aptpl_active) { |
2810 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, | 2809 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, |
2811 | &pr_reg->pr_aptpl_buf[0], | 2810 | &pr_reg->pr_aptpl_buf[0], |
2812 | pr_tmpl->pr_aptpl_buf_len); | 2811 | pr_tmpl->pr_aptpl_buf_len); |
2813 | if (!ret) | 2812 | if (!ret) |
2814 | pr_debug("SPC-3 PR: Updated APTPL metadata for RELEASE\n"); | 2813 | pr_debug("SPC-3 PR: Updated APTPL metadata for RELEASE\n"); |
2815 | } | 2814 | } |
2816 | 2815 | ||
2817 | core_scsi3_put_pr_reg(pr_reg); | 2816 | core_scsi3_put_pr_reg(pr_reg); |
2818 | return 0; | 2817 | return 0; |
2819 | } | 2818 | } |
2820 | 2819 | ||
2821 | static int core_scsi3_emulate_pro_clear( | 2820 | static int core_scsi3_emulate_pro_clear( |
2822 | struct se_cmd *cmd, | 2821 | struct se_cmd *cmd, |
2823 | u64 res_key) | 2822 | u64 res_key) |
2824 | { | 2823 | { |
2825 | struct se_device *dev = cmd->se_dev; | 2824 | struct se_device *dev = cmd->se_dev; |
2826 | struct se_node_acl *pr_reg_nacl; | 2825 | struct se_node_acl *pr_reg_nacl; |
2827 | struct se_session *se_sess = cmd->se_sess; | 2826 | struct se_session *se_sess = cmd->se_sess; |
2828 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 2827 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
2829 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; | 2828 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; |
2830 | u32 pr_res_mapped_lun = 0; | 2829 | u32 pr_res_mapped_lun = 0; |
2831 | int calling_it_nexus = 0; | 2830 | int calling_it_nexus = 0; |
2832 | /* | 2831 | /* |
2833 | * Locate the existing *pr_reg via struct se_node_acl pointers | 2832 | * Locate the existing *pr_reg via struct se_node_acl pointers |
2834 | */ | 2833 | */ |
2835 | pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, | 2834 | pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, |
2836 | se_sess->se_node_acl, se_sess); | 2835 | se_sess->se_node_acl, se_sess); |
2837 | if (!pr_reg_n) { | 2836 | if (!pr_reg_n) { |
2838 | pr_err("SPC-3 PR: Unable to locate" | 2837 | pr_err("SPC-3 PR: Unable to locate" |
2839 | " PR_REGISTERED *pr_reg for CLEAR\n"); | 2838 | " PR_REGISTERED *pr_reg for CLEAR\n"); |
2840 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2839 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2841 | return -EINVAL; | 2840 | return -EINVAL; |
2842 | } | 2841 | } |
2843 | /* | 2842 | /* |
2844 | * From spc4r17 section 5.7.11.6, Clearing: | 2843 | * From spc4r17 section 5.7.11.6, Clearing: |
2845 | * | 2844 | * |
2846 | * Any application client may release the persistent reservation and | 2845 | * Any application client may release the persistent reservation and |
2847 | * remove all registrations from a device server by issuing a | 2846 | * remove all registrations from a device server by issuing a |
2848 | * PERSISTENT RESERVE OUT command with CLEAR service action through a | 2847 | * PERSISTENT RESERVE OUT command with CLEAR service action through a |
2849 | * registered I_T nexus with the following parameter: | 2848 | * registered I_T nexus with the following parameter: |
2850 | * | 2849 | * |
2851 | * a) RESERVATION KEY field set to the value of the reservation key | 2850 | * a) RESERVATION KEY field set to the value of the reservation key |
2852 | * that is registered with the logical unit for the I_T nexus. | 2851 | * that is registered with the logical unit for the I_T nexus. |
2853 | */ | 2852 | */ |
2854 | if (res_key != pr_reg_n->pr_res_key) { | 2853 | if (res_key != pr_reg_n->pr_res_key) { |
2855 | pr_err("SPC-3 PR REGISTER: Received" | 2854 | pr_err("SPC-3 PR REGISTER: Received" |
2856 | " res_key: 0x%016Lx does not match" | 2855 | " res_key: 0x%016Lx does not match" |
2857 | " existing SA REGISTER res_key:" | 2856 | " existing SA REGISTER res_key:" |
2858 | " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key); | 2857 | " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key); |
2859 | core_scsi3_put_pr_reg(pr_reg_n); | 2858 | core_scsi3_put_pr_reg(pr_reg_n); |
2860 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 2859 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
2861 | return -EINVAL; | 2860 | return -EINVAL; |
2862 | } | 2861 | } |
2863 | /* | 2862 | /* |
2864 | * a) Release the persistent reservation, if any; | 2863 | * a) Release the persistent reservation, if any; |
2865 | */ | 2864 | */ |
2866 | spin_lock(&dev->dev_reservation_lock); | 2865 | spin_lock(&dev->dev_reservation_lock); |
2867 | pr_res_holder = dev->dev_pr_res_holder; | 2866 | pr_res_holder = dev->dev_pr_res_holder; |
2868 | if (pr_res_holder) { | 2867 | if (pr_res_holder) { |
2869 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 2868 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
2870 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, | 2869 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, |
2871 | pr_res_holder, 0); | 2870 | pr_res_holder, 0); |
2872 | } | 2871 | } |
2873 | spin_unlock(&dev->dev_reservation_lock); | 2872 | spin_unlock(&dev->dev_reservation_lock); |
2874 | /* | 2873 | /* |
2875 | * b) Remove all registration(s) (see spc4r17 5.7.7); | 2874 | * b) Remove all registration(s) (see spc4r17 5.7.7); |
2876 | */ | 2875 | */ |
2877 | spin_lock(&pr_tmpl->registration_lock); | 2876 | spin_lock(&pr_tmpl->registration_lock); |
2878 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 2877 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
2879 | &pr_tmpl->registration_list, pr_reg_list) { | 2878 | &pr_tmpl->registration_list, pr_reg_list) { |
2880 | 2879 | ||
2881 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; | 2880 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; |
2882 | pr_reg_nacl = pr_reg->pr_reg_nacl; | 2881 | pr_reg_nacl = pr_reg->pr_reg_nacl; |
2883 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; | 2882 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; |
2884 | __core_scsi3_free_registration(dev, pr_reg, NULL, | 2883 | __core_scsi3_free_registration(dev, pr_reg, NULL, |
2885 | calling_it_nexus); | 2884 | calling_it_nexus); |
2886 | /* | 2885 | /* |
2887 | * e) Establish a unit attention condition for the initiator | 2886 | * e) Establish a unit attention condition for the initiator |
2888 | * port associated with every registered I_T nexus other | 2887 | * port associated with every registered I_T nexus other |
2889 | * than the I_T nexus on which the PERSISTENT RESERVE OUT | 2888 | * than the I_T nexus on which the PERSISTENT RESERVE OUT |
2890 | * command with CLEAR service action was received, with the | 2889 | * command with CLEAR service action was received, with the |
2891 | * additional sense code set to RESERVATIONS PREEMPTED. | 2890 | * additional sense code set to RESERVATIONS PREEMPTED. |
2892 | */ | 2891 | */ |
2893 | if (!calling_it_nexus) | 2892 | if (!calling_it_nexus) |
2894 | core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, | 2893 | core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, |
2895 | 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED); | 2894 | 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED); |
2896 | } | 2895 | } |
2897 | spin_unlock(&pr_tmpl->registration_lock); | 2896 | spin_unlock(&pr_tmpl->registration_lock); |
2898 | 2897 | ||
2899 | pr_debug("SPC-3 PR [%s] Service Action: CLEAR complete\n", | 2898 | pr_debug("SPC-3 PR [%s] Service Action: CLEAR complete\n", |
2900 | cmd->se_tfo->get_fabric_name()); | 2899 | cmd->se_tfo->get_fabric_name()); |
2901 | 2900 | ||
2902 | if (pr_tmpl->pr_aptpl_active) { | 2901 | if (pr_tmpl->pr_aptpl_active) { |
2903 | core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); | 2902 | core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); |
2904 | pr_debug("SPC-3 PR: Updated APTPL metadata" | 2903 | pr_debug("SPC-3 PR: Updated APTPL metadata" |
2905 | " for CLEAR\n"); | 2904 | " for CLEAR\n"); |
2906 | } | 2905 | } |
2907 | 2906 | ||
2908 | core_scsi3_pr_generation(dev); | 2907 | core_scsi3_pr_generation(dev); |
2909 | return 0; | 2908 | return 0; |
2910 | } | 2909 | } |
2911 | 2910 | ||
2912 | /* | 2911 | /* |
2913 | * Called with struct se_device->dev_reservation_lock held. | 2912 | * Called with struct se_device->dev_reservation_lock held. |
2914 | */ | 2913 | */ |
2915 | static void __core_scsi3_complete_pro_preempt( | 2914 | static void __core_scsi3_complete_pro_preempt( |
2916 | struct se_device *dev, | 2915 | struct se_device *dev, |
2917 | struct t10_pr_registration *pr_reg, | 2916 | struct t10_pr_registration *pr_reg, |
2918 | struct list_head *preempt_and_abort_list, | 2917 | struct list_head *preempt_and_abort_list, |
2919 | int type, | 2918 | int type, |
2920 | int scope, | 2919 | int scope, |
2921 | int abort) | 2920 | int abort) |
2922 | { | 2921 | { |
2923 | struct se_node_acl *nacl = pr_reg->pr_reg_nacl; | 2922 | struct se_node_acl *nacl = pr_reg->pr_reg_nacl; |
2924 | struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; | 2923 | struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; |
2925 | char i_buf[PR_REG_ISID_ID_LEN]; | 2924 | char i_buf[PR_REG_ISID_ID_LEN]; |
2926 | int prf_isid; | 2925 | int prf_isid; |
2927 | 2926 | ||
2928 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 2927 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
2929 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 2928 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
2930 | PR_REG_ISID_ID_LEN); | 2929 | PR_REG_ISID_ID_LEN); |
2931 | /* | 2930 | /* |
2932 | * Do an implict RELEASE of the existing reservation. | 2931 | * Do an implict RELEASE of the existing reservation. |
2933 | */ | 2932 | */ |
2934 | if (dev->dev_pr_res_holder) | 2933 | if (dev->dev_pr_res_holder) |
2935 | __core_scsi3_complete_pro_release(dev, nacl, | 2934 | __core_scsi3_complete_pro_release(dev, nacl, |
2936 | dev->dev_pr_res_holder, 0); | 2935 | dev->dev_pr_res_holder, 0); |
2937 | 2936 | ||
2938 | dev->dev_pr_res_holder = pr_reg; | 2937 | dev->dev_pr_res_holder = pr_reg; |
2939 | pr_reg->pr_res_holder = 1; | 2938 | pr_reg->pr_res_holder = 1; |
2940 | pr_reg->pr_res_type = type; | 2939 | pr_reg->pr_res_type = type; |
2941 | pr_reg->pr_res_scope = scope; | 2940 | pr_reg->pr_res_scope = scope; |
2942 | 2941 | ||
2943 | pr_debug("SPC-3 PR [%s] Service Action: PREEMPT%s created new" | 2942 | pr_debug("SPC-3 PR [%s] Service Action: PREEMPT%s created new" |
2944 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", | 2943 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", |
2945 | tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", | 2944 | tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", |
2946 | core_scsi3_pr_dump_type(type), | 2945 | core_scsi3_pr_dump_type(type), |
2947 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); | 2946 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); |
2948 | pr_debug("SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n", | 2947 | pr_debug("SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n", |
2949 | tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", | 2948 | tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", |
2950 | nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); | 2949 | nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); |
2951 | /* | 2950 | /* |
2952 | * For PREEMPT_AND_ABORT, add the preempting reservation's | 2951 | * For PREEMPT_AND_ABORT, add the preempting reservation's |
2953 | * struct t10_pr_registration to the list that will be compared | 2952 | * struct t10_pr_registration to the list that will be compared |
2954 | * against received CDBs.. | 2953 | * against received CDBs.. |
2955 | */ | 2954 | */ |
2956 | if (preempt_and_abort_list) | 2955 | if (preempt_and_abort_list) |
2957 | list_add_tail(&pr_reg->pr_reg_abort_list, | 2956 | list_add_tail(&pr_reg->pr_reg_abort_list, |
2958 | preempt_and_abort_list); | 2957 | preempt_and_abort_list); |
2959 | } | 2958 | } |
2960 | 2959 | ||
2961 | static void core_scsi3_release_preempt_and_abort( | 2960 | static void core_scsi3_release_preempt_and_abort( |
2962 | struct list_head *preempt_and_abort_list, | 2961 | struct list_head *preempt_and_abort_list, |
2963 | struct t10_pr_registration *pr_reg_holder) | 2962 | struct t10_pr_registration *pr_reg_holder) |
2964 | { | 2963 | { |
2965 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; | 2964 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; |
2966 | 2965 | ||
2967 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list, | 2966 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list, |
2968 | pr_reg_abort_list) { | 2967 | pr_reg_abort_list) { |
2969 | 2968 | ||
2970 | list_del(&pr_reg->pr_reg_abort_list); | 2969 | list_del(&pr_reg->pr_reg_abort_list); |
2971 | if (pr_reg_holder == pr_reg) | 2970 | if (pr_reg_holder == pr_reg) |
2972 | continue; | 2971 | continue; |
2973 | if (pr_reg->pr_res_holder) { | 2972 | if (pr_reg->pr_res_holder) { |
2974 | pr_warn("pr_reg->pr_res_holder still set\n"); | 2973 | pr_warn("pr_reg->pr_res_holder still set\n"); |
2975 | continue; | 2974 | continue; |
2976 | } | 2975 | } |
2977 | 2976 | ||
2978 | pr_reg->pr_reg_deve = NULL; | 2977 | pr_reg->pr_reg_deve = NULL; |
2979 | pr_reg->pr_reg_nacl = NULL; | 2978 | pr_reg->pr_reg_nacl = NULL; |
2980 | kfree(pr_reg->pr_aptpl_buf); | 2979 | kfree(pr_reg->pr_aptpl_buf); |
2981 | kmem_cache_free(t10_pr_reg_cache, pr_reg); | 2980 | kmem_cache_free(t10_pr_reg_cache, pr_reg); |
2982 | } | 2981 | } |
2983 | } | 2982 | } |
2984 | 2983 | ||
2985 | static int core_scsi3_pro_preempt( | 2984 | static int core_scsi3_pro_preempt( |
2986 | struct se_cmd *cmd, | 2985 | struct se_cmd *cmd, |
2987 | int type, | 2986 | int type, |
2988 | int scope, | 2987 | int scope, |
2989 | u64 res_key, | 2988 | u64 res_key, |
2990 | u64 sa_res_key, | 2989 | u64 sa_res_key, |
2991 | int abort) | 2990 | int abort) |
2992 | { | 2991 | { |
2993 | struct se_device *dev = cmd->se_dev; | 2992 | struct se_device *dev = cmd->se_dev; |
2994 | struct se_dev_entry *se_deve; | 2993 | struct se_dev_entry *se_deve; |
2995 | struct se_node_acl *pr_reg_nacl; | 2994 | struct se_node_acl *pr_reg_nacl; |
2996 | struct se_session *se_sess = cmd->se_sess; | 2995 | struct se_session *se_sess = cmd->se_sess; |
2997 | struct list_head preempt_and_abort_list; | 2996 | LIST_HEAD(preempt_and_abort_list); |
2998 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; | 2997 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; |
2999 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 2998 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
3000 | u32 pr_res_mapped_lun = 0; | 2999 | u32 pr_res_mapped_lun = 0; |
3001 | int all_reg = 0, calling_it_nexus = 0, released_regs = 0; | 3000 | int all_reg = 0, calling_it_nexus = 0, released_regs = 0; |
3002 | int prh_type = 0, prh_scope = 0, ret; | 3001 | int prh_type = 0, prh_scope = 0, ret; |
3003 | 3002 | ||
3004 | if (!se_sess) { | 3003 | if (!se_sess) { |
3005 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3004 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3006 | return -EINVAL; | 3005 | return -EINVAL; |
3007 | } | 3006 | } |
3008 | 3007 | ||
3009 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; | 3008 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; |
3010 | pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, | 3009 | pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, |
3011 | se_sess); | 3010 | se_sess); |
3012 | if (!pr_reg_n) { | 3011 | if (!pr_reg_n) { |
3013 | pr_err("SPC-3 PR: Unable to locate" | 3012 | pr_err("SPC-3 PR: Unable to locate" |
3014 | " PR_REGISTERED *pr_reg for PREEMPT%s\n", | 3013 | " PR_REGISTERED *pr_reg for PREEMPT%s\n", |
3015 | (abort) ? "_AND_ABORT" : ""); | 3014 | (abort) ? "_AND_ABORT" : ""); |
3016 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3015 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3017 | return -EINVAL; | 3016 | return -EINVAL; |
3018 | } | 3017 | } |
3019 | if (pr_reg_n->pr_res_key != res_key) { | 3018 | if (pr_reg_n->pr_res_key != res_key) { |
3020 | core_scsi3_put_pr_reg(pr_reg_n); | 3019 | core_scsi3_put_pr_reg(pr_reg_n); |
3021 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3020 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3022 | return -EINVAL; | 3021 | return -EINVAL; |
3023 | } | 3022 | } |
3024 | if (scope != PR_SCOPE_LU_SCOPE) { | 3023 | if (scope != PR_SCOPE_LU_SCOPE) { |
3025 | pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); | 3024 | pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); |
3026 | core_scsi3_put_pr_reg(pr_reg_n); | 3025 | core_scsi3_put_pr_reg(pr_reg_n); |
3027 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3026 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3028 | return -EINVAL; | 3027 | return -EINVAL; |
3029 | } | 3028 | } |
3030 | INIT_LIST_HEAD(&preempt_and_abort_list); | ||
3031 | 3029 | ||
3032 | spin_lock(&dev->dev_reservation_lock); | 3030 | spin_lock(&dev->dev_reservation_lock); |
3033 | pr_res_holder = dev->dev_pr_res_holder; | 3031 | pr_res_holder = dev->dev_pr_res_holder; |
3034 | if (pr_res_holder && | 3032 | if (pr_res_holder && |
3035 | ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | 3033 | ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || |
3036 | (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))) | 3034 | (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))) |
3037 | all_reg = 1; | 3035 | all_reg = 1; |
3038 | 3036 | ||
3039 | if (!all_reg && !sa_res_key) { | 3037 | if (!all_reg && !sa_res_key) { |
3040 | spin_unlock(&dev->dev_reservation_lock); | 3038 | spin_unlock(&dev->dev_reservation_lock); |
3041 | core_scsi3_put_pr_reg(pr_reg_n); | 3039 | core_scsi3_put_pr_reg(pr_reg_n); |
3042 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3040 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3043 | return -EINVAL; | 3041 | return -EINVAL; |
3044 | } | 3042 | } |
3045 | /* | 3043 | /* |
3046 | * From spc4r17, section 5.7.11.4.4 Removing Registrations: | 3044 | * From spc4r17, section 5.7.11.4.4 Removing Registrations: |
3047 | * | 3045 | * |
3048 | * If the SERVICE ACTION RESERVATION KEY field does not identify a | 3046 | * If the SERVICE ACTION RESERVATION KEY field does not identify a |
3049 | * persistent reservation holder or there is no persistent reservation | 3047 | * persistent reservation holder or there is no persistent reservation |
3050 | * holder (i.e., there is no persistent reservation), then the device | 3048 | * holder (i.e., there is no persistent reservation), then the device |
3051 | * server shall perform a preempt by doing the following in an | 3049 | * server shall perform a preempt by doing the following in an |
3052 | * uninterrupted series of actions. (See below..) | 3050 | * uninterrupted series of actions. (See below..) |
3053 | */ | 3051 | */ |
3054 | if (!pr_res_holder || (pr_res_holder->pr_res_key != sa_res_key)) { | 3052 | if (!pr_res_holder || (pr_res_holder->pr_res_key != sa_res_key)) { |
3055 | /* | 3053 | /* |
3056 | * No existing or SA Reservation Key matching reservations.. | 3054 | * No existing or SA Reservation Key matching reservations.. |
3057 | * | 3055 | * |
3058 | * PROUT SA PREEMPT with All Registrant type reservations are | 3056 | * PROUT SA PREEMPT with All Registrant type reservations are |
3059 | * allowed to be processed without a matching SA Reservation Key | 3057 | * allowed to be processed without a matching SA Reservation Key |
3060 | */ | 3058 | */ |
3061 | spin_lock(&pr_tmpl->registration_lock); | 3059 | spin_lock(&pr_tmpl->registration_lock); |
3062 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 3060 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
3063 | &pr_tmpl->registration_list, pr_reg_list) { | 3061 | &pr_tmpl->registration_list, pr_reg_list) { |
3064 | /* | 3062 | /* |
3065 | * Removing of registrations in non all registrants | 3063 | * Removing of registrations in non all registrants |
3066 | * type reservations without a matching SA reservation | 3064 | * type reservations without a matching SA reservation |
3067 | * key. | 3065 | * key. |
3068 | * | 3066 | * |
3069 | * a) Remove the registrations for all I_T nexuses | 3067 | * a) Remove the registrations for all I_T nexuses |
3070 | * specified by the SERVICE ACTION RESERVATION KEY | 3068 | * specified by the SERVICE ACTION RESERVATION KEY |
3071 | * field; | 3069 | * field; |
3072 | * b) Ignore the contents of the SCOPE and TYPE fields; | 3070 | * b) Ignore the contents of the SCOPE and TYPE fields; |
3073 | * c) Process tasks as defined in 5.7.1; and | 3071 | * c) Process tasks as defined in 5.7.1; and |
3074 | * d) Establish a unit attention condition for the | 3072 | * d) Establish a unit attention condition for the |
3075 | * initiator port associated with every I_T nexus | 3073 | * initiator port associated with every I_T nexus |
3076 | * that lost its registration other than the I_T | 3074 | * that lost its registration other than the I_T |
3077 | * nexus on which the PERSISTENT RESERVE OUT command | 3075 | * nexus on which the PERSISTENT RESERVE OUT command |
3078 | * was received, with the additional sense code set | 3076 | * was received, with the additional sense code set |
3079 | * to REGISTRATIONS PREEMPTED. | 3077 | * to REGISTRATIONS PREEMPTED. |
3080 | */ | 3078 | */ |
3081 | if (!all_reg) { | 3079 | if (!all_reg) { |
3082 | if (pr_reg->pr_res_key != sa_res_key) | 3080 | if (pr_reg->pr_res_key != sa_res_key) |
3083 | continue; | 3081 | continue; |
3084 | 3082 | ||
3085 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; | 3083 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; |
3086 | pr_reg_nacl = pr_reg->pr_reg_nacl; | 3084 | pr_reg_nacl = pr_reg->pr_reg_nacl; |
3087 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; | 3085 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; |
3088 | __core_scsi3_free_registration(dev, pr_reg, | 3086 | __core_scsi3_free_registration(dev, pr_reg, |
3089 | (abort) ? &preempt_and_abort_list : | 3087 | (abort) ? &preempt_and_abort_list : |
3090 | NULL, calling_it_nexus); | 3088 | NULL, calling_it_nexus); |
3091 | released_regs++; | 3089 | released_regs++; |
3092 | } else { | 3090 | } else { |
3093 | /* | 3091 | /* |
3094 | * Case for any existing all registrants type | 3092 | * Case for any existing all registrants type |
3095 | * reservation, follow logic in spc4r17 section | 3093 | * reservation, follow logic in spc4r17 section |
3096 | * 5.7.11.4 Preempting, Table 52 and Figure 7. | 3094 | * 5.7.11.4 Preempting, Table 52 and Figure 7. |
3097 | * | 3095 | * |
3098 | * For a ZERO SA Reservation key, release | 3096 | * For a ZERO SA Reservation key, release |
3099 | * all other registrations and do an implict | 3097 | * all other registrations and do an implict |
3100 | * release of active persistent reservation. | 3098 | * release of active persistent reservation. |
3101 | * | 3099 | * |
3102 | * For a non-ZERO SA Reservation key, only | 3100 | * For a non-ZERO SA Reservation key, only |
3103 | * release the matching reservation key from | 3101 | * release the matching reservation key from |
3104 | * registrations. | 3102 | * registrations. |
3105 | */ | 3103 | */ |
3106 | if ((sa_res_key) && | 3104 | if ((sa_res_key) && |
3107 | (pr_reg->pr_res_key != sa_res_key)) | 3105 | (pr_reg->pr_res_key != sa_res_key)) |
3108 | continue; | 3106 | continue; |
3109 | 3107 | ||
3110 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; | 3108 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; |
3111 | if (calling_it_nexus) | 3109 | if (calling_it_nexus) |
3112 | continue; | 3110 | continue; |
3113 | 3111 | ||
3114 | pr_reg_nacl = pr_reg->pr_reg_nacl; | 3112 | pr_reg_nacl = pr_reg->pr_reg_nacl; |
3115 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; | 3113 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; |
3116 | __core_scsi3_free_registration(dev, pr_reg, | 3114 | __core_scsi3_free_registration(dev, pr_reg, |
3117 | (abort) ? &preempt_and_abort_list : | 3115 | (abort) ? &preempt_and_abort_list : |
3118 | NULL, 0); | 3116 | NULL, 0); |
3119 | released_regs++; | 3117 | released_regs++; |
3120 | } | 3118 | } |
3121 | if (!calling_it_nexus) | 3119 | if (!calling_it_nexus) |
3122 | core_scsi3_ua_allocate(pr_reg_nacl, | 3120 | core_scsi3_ua_allocate(pr_reg_nacl, |
3123 | pr_res_mapped_lun, 0x2A, | 3121 | pr_res_mapped_lun, 0x2A, |
3124 | ASCQ_2AH_REGISTRATIONS_PREEMPTED); | 3122 | ASCQ_2AH_REGISTRATIONS_PREEMPTED); |
3125 | } | 3123 | } |
3126 | spin_unlock(&pr_tmpl->registration_lock); | 3124 | spin_unlock(&pr_tmpl->registration_lock); |
3127 | /* | 3125 | /* |
3128 | * If a PERSISTENT RESERVE OUT with a PREEMPT service action or | 3126 | * If a PERSISTENT RESERVE OUT with a PREEMPT service action or |
3129 | * a PREEMPT AND ABORT service action sets the SERVICE ACTION | 3127 | * a PREEMPT AND ABORT service action sets the SERVICE ACTION |
3130 | * RESERVATION KEY field to a value that does not match any | 3128 | * RESERVATION KEY field to a value that does not match any |
3131 | * registered reservation key, then the device server shall | 3129 | * registered reservation key, then the device server shall |
3132 | * complete the command with RESERVATION CONFLICT status. | 3130 | * complete the command with RESERVATION CONFLICT status. |
3133 | */ | 3131 | */ |
3134 | if (!released_regs) { | 3132 | if (!released_regs) { |
3135 | spin_unlock(&dev->dev_reservation_lock); | 3133 | spin_unlock(&dev->dev_reservation_lock); |
3136 | core_scsi3_put_pr_reg(pr_reg_n); | 3134 | core_scsi3_put_pr_reg(pr_reg_n); |
3137 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3135 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3138 | return -EINVAL; | 3136 | return -EINVAL; |
3139 | } | 3137 | } |
3140 | /* | 3138 | /* |
3141 | * For an existing all registrants type reservation | 3139 | * For an existing all registrants type reservation |
3142 | * with a zero SA rservation key, preempt the existing | 3140 | * with a zero SA rservation key, preempt the existing |
3143 | * reservation with the new PR type and scope. | 3141 | * reservation with the new PR type and scope. |
3144 | */ | 3142 | */ |
3145 | if (pr_res_holder && all_reg && !(sa_res_key)) { | 3143 | if (pr_res_holder && all_reg && !(sa_res_key)) { |
3146 | __core_scsi3_complete_pro_preempt(dev, pr_reg_n, | 3144 | __core_scsi3_complete_pro_preempt(dev, pr_reg_n, |
3147 | (abort) ? &preempt_and_abort_list : NULL, | 3145 | (abort) ? &preempt_and_abort_list : NULL, |
3148 | type, scope, abort); | 3146 | type, scope, abort); |
3149 | 3147 | ||
3150 | if (abort) | 3148 | if (abort) |
3151 | core_scsi3_release_preempt_and_abort( | 3149 | core_scsi3_release_preempt_and_abort( |
3152 | &preempt_and_abort_list, pr_reg_n); | 3150 | &preempt_and_abort_list, pr_reg_n); |
3153 | } | 3151 | } |
3154 | spin_unlock(&dev->dev_reservation_lock); | 3152 | spin_unlock(&dev->dev_reservation_lock); |
3155 | 3153 | ||
3156 | if (pr_tmpl->pr_aptpl_active) { | 3154 | if (pr_tmpl->pr_aptpl_active) { |
3157 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, | 3155 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, |
3158 | &pr_reg_n->pr_aptpl_buf[0], | 3156 | &pr_reg_n->pr_aptpl_buf[0], |
3159 | pr_tmpl->pr_aptpl_buf_len); | 3157 | pr_tmpl->pr_aptpl_buf_len); |
3160 | if (!ret) | 3158 | if (!ret) |
3161 | pr_debug("SPC-3 PR: Updated APTPL" | 3159 | pr_debug("SPC-3 PR: Updated APTPL" |
3162 | " metadata for PREEMPT%s\n", (abort) ? | 3160 | " metadata for PREEMPT%s\n", (abort) ? |
3163 | "_AND_ABORT" : ""); | 3161 | "_AND_ABORT" : ""); |
3164 | } | 3162 | } |
3165 | 3163 | ||
3166 | core_scsi3_put_pr_reg(pr_reg_n); | 3164 | core_scsi3_put_pr_reg(pr_reg_n); |
3167 | core_scsi3_pr_generation(cmd->se_dev); | 3165 | core_scsi3_pr_generation(cmd->se_dev); |
3168 | return 0; | 3166 | return 0; |
3169 | } | 3167 | } |
3170 | /* | 3168 | /* |
3171 | * The PREEMPTing SA reservation key matches that of the | 3169 | * The PREEMPTing SA reservation key matches that of the |
3172 | * existing persistent reservation, first, we check if | 3170 | * existing persistent reservation, first, we check if |
3173 | * we are preempting our own reservation. | 3171 | * we are preempting our own reservation. |
3174 | * From spc4r17, section 5.7.11.4.3 Preempting | 3172 | * From spc4r17, section 5.7.11.4.3 Preempting |
3175 | * persistent reservations and registration handling | 3173 | * persistent reservations and registration handling |
3176 | * | 3174 | * |
3177 | * If an all registrants persistent reservation is not | 3175 | * If an all registrants persistent reservation is not |
3178 | * present, it is not an error for the persistent | 3176 | * present, it is not an error for the persistent |
3179 | * reservation holder to preempt itself (i.e., a | 3177 | * reservation holder to preempt itself (i.e., a |
3180 | * PERSISTENT RESERVE OUT with a PREEMPT service action | 3178 | * PERSISTENT RESERVE OUT with a PREEMPT service action |
3181 | * or a PREEMPT AND ABORT service action with the | 3179 | * or a PREEMPT AND ABORT service action with the |
3182 | * SERVICE ACTION RESERVATION KEY value equal to the | 3180 | * SERVICE ACTION RESERVATION KEY value equal to the |
3183 | * persistent reservation holder's reservation key that | 3181 | * persistent reservation holder's reservation key that |
3184 | * is received from the persistent reservation holder). | 3182 | * is received from the persistent reservation holder). |
3185 | * In that case, the device server shall establish the | 3183 | * In that case, the device server shall establish the |
3186 | * new persistent reservation and maintain the | 3184 | * new persistent reservation and maintain the |
3187 | * registration. | 3185 | * registration. |
3188 | */ | 3186 | */ |
3189 | prh_type = pr_res_holder->pr_res_type; | 3187 | prh_type = pr_res_holder->pr_res_type; |
3190 | prh_scope = pr_res_holder->pr_res_scope; | 3188 | prh_scope = pr_res_holder->pr_res_scope; |
3191 | /* | 3189 | /* |
3192 | * If the SERVICE ACTION RESERVATION KEY field identifies a | 3190 | * If the SERVICE ACTION RESERVATION KEY field identifies a |
3193 | * persistent reservation holder (see 5.7.10), the device | 3191 | * persistent reservation holder (see 5.7.10), the device |
3194 | * server shall perform a preempt by doing the following as | 3192 | * server shall perform a preempt by doing the following as |
3195 | * an uninterrupted series of actions: | 3193 | * an uninterrupted series of actions: |
3196 | * | 3194 | * |
3197 | * a) Release the persistent reservation for the holder | 3195 | * a) Release the persistent reservation for the holder |
3198 | * identified by the SERVICE ACTION RESERVATION KEY field; | 3196 | * identified by the SERVICE ACTION RESERVATION KEY field; |
3199 | */ | 3197 | */ |
3200 | if (pr_reg_n != pr_res_holder) | 3198 | if (pr_reg_n != pr_res_holder) |
3201 | __core_scsi3_complete_pro_release(dev, | 3199 | __core_scsi3_complete_pro_release(dev, |
3202 | pr_res_holder->pr_reg_nacl, | 3200 | pr_res_holder->pr_reg_nacl, |
3203 | dev->dev_pr_res_holder, 0); | 3201 | dev->dev_pr_res_holder, 0); |
3204 | /* | 3202 | /* |
3205 | * b) Remove the registrations for all I_T nexuses identified | 3203 | * b) Remove the registrations for all I_T nexuses identified |
3206 | * by the SERVICE ACTION RESERVATION KEY field, except the | 3204 | * by the SERVICE ACTION RESERVATION KEY field, except the |
3207 | * I_T nexus that is being used for the PERSISTENT RESERVE | 3205 | * I_T nexus that is being used for the PERSISTENT RESERVE |
3208 | * OUT command. If an all registrants persistent reservation | 3206 | * OUT command. If an all registrants persistent reservation |
3209 | * is present and the SERVICE ACTION RESERVATION KEY field | 3207 | * is present and the SERVICE ACTION RESERVATION KEY field |
3210 | * is set to zero, then all registrations shall be removed | 3208 | * is set to zero, then all registrations shall be removed |
3211 | * except for that of the I_T nexus that is being used for | 3209 | * except for that of the I_T nexus that is being used for |
3212 | * the PERSISTENT RESERVE OUT command; | 3210 | * the PERSISTENT RESERVE OUT command; |
3213 | */ | 3211 | */ |
3214 | spin_lock(&pr_tmpl->registration_lock); | 3212 | spin_lock(&pr_tmpl->registration_lock); |
3215 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 3213 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
3216 | &pr_tmpl->registration_list, pr_reg_list) { | 3214 | &pr_tmpl->registration_list, pr_reg_list) { |
3217 | 3215 | ||
3218 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; | 3216 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; |
3219 | if (calling_it_nexus) | 3217 | if (calling_it_nexus) |
3220 | continue; | 3218 | continue; |
3221 | 3219 | ||
3222 | if (pr_reg->pr_res_key != sa_res_key) | 3220 | if (pr_reg->pr_res_key != sa_res_key) |
3223 | continue; | 3221 | continue; |
3224 | 3222 | ||
3225 | pr_reg_nacl = pr_reg->pr_reg_nacl; | 3223 | pr_reg_nacl = pr_reg->pr_reg_nacl; |
3226 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; | 3224 | pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; |
3227 | __core_scsi3_free_registration(dev, pr_reg, | 3225 | __core_scsi3_free_registration(dev, pr_reg, |
3228 | (abort) ? &preempt_and_abort_list : NULL, | 3226 | (abort) ? &preempt_and_abort_list : NULL, |
3229 | calling_it_nexus); | 3227 | calling_it_nexus); |
3230 | /* | 3228 | /* |
3231 | * e) Establish a unit attention condition for the initiator | 3229 | * e) Establish a unit attention condition for the initiator |
3232 | * port associated with every I_T nexus that lost its | 3230 | * port associated with every I_T nexus that lost its |
3233 | * persistent reservation and/or registration, with the | 3231 | * persistent reservation and/or registration, with the |
3234 | * additional sense code set to REGISTRATIONS PREEMPTED; | 3232 | * additional sense code set to REGISTRATIONS PREEMPTED; |
3235 | */ | 3233 | */ |
3236 | core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, | 3234 | core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, |
3237 | ASCQ_2AH_REGISTRATIONS_PREEMPTED); | 3235 | ASCQ_2AH_REGISTRATIONS_PREEMPTED); |
3238 | } | 3236 | } |
3239 | spin_unlock(&pr_tmpl->registration_lock); | 3237 | spin_unlock(&pr_tmpl->registration_lock); |
3240 | /* | 3238 | /* |
3241 | * c) Establish a persistent reservation for the preempting | 3239 | * c) Establish a persistent reservation for the preempting |
3242 | * I_T nexus using the contents of the SCOPE and TYPE fields; | 3240 | * I_T nexus using the contents of the SCOPE and TYPE fields; |
3243 | */ | 3241 | */ |
3244 | __core_scsi3_complete_pro_preempt(dev, pr_reg_n, | 3242 | __core_scsi3_complete_pro_preempt(dev, pr_reg_n, |
3245 | (abort) ? &preempt_and_abort_list : NULL, | 3243 | (abort) ? &preempt_and_abort_list : NULL, |
3246 | type, scope, abort); | 3244 | type, scope, abort); |
3247 | /* | 3245 | /* |
3248 | * d) Process tasks as defined in 5.7.1; | 3246 | * d) Process tasks as defined in 5.7.1; |
3249 | * e) See above.. | 3247 | * e) See above.. |
3250 | * f) If the type or scope has changed, then for every I_T nexus | 3248 | * f) If the type or scope has changed, then for every I_T nexus |
3251 | * whose reservation key was not removed, except for the I_T | 3249 | * whose reservation key was not removed, except for the I_T |
3252 | * nexus on which the PERSISTENT RESERVE OUT command was | 3250 | * nexus on which the PERSISTENT RESERVE OUT command was |
3253 | * received, the device server shall establish a unit | 3251 | * received, the device server shall establish a unit |
3254 | * attention condition for the initiator port associated with | 3252 | * attention condition for the initiator port associated with |
3255 | * that I_T nexus, with the additional sense code set to | 3253 | * that I_T nexus, with the additional sense code set to |
3256 | * RESERVATIONS RELEASED. If the type or scope have not | 3254 | * RESERVATIONS RELEASED. If the type or scope have not |
3257 | * changed, then no unit attention condition(s) shall be | 3255 | * changed, then no unit attention condition(s) shall be |
3258 | * established for this reason. | 3256 | * established for this reason. |
3259 | */ | 3257 | */ |
3260 | if ((prh_type != type) || (prh_scope != scope)) { | 3258 | if ((prh_type != type) || (prh_scope != scope)) { |
3261 | spin_lock(&pr_tmpl->registration_lock); | 3259 | spin_lock(&pr_tmpl->registration_lock); |
3262 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 3260 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
3263 | &pr_tmpl->registration_list, pr_reg_list) { | 3261 | &pr_tmpl->registration_list, pr_reg_list) { |
3264 | 3262 | ||
3265 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; | 3263 | calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; |
3266 | if (calling_it_nexus) | 3264 | if (calling_it_nexus) |
3267 | continue; | 3265 | continue; |
3268 | 3266 | ||
3269 | core_scsi3_ua_allocate(pr_reg->pr_reg_nacl, | 3267 | core_scsi3_ua_allocate(pr_reg->pr_reg_nacl, |
3270 | pr_reg->pr_res_mapped_lun, 0x2A, | 3268 | pr_reg->pr_res_mapped_lun, 0x2A, |
3271 | ASCQ_2AH_RESERVATIONS_RELEASED); | 3269 | ASCQ_2AH_RESERVATIONS_RELEASED); |
3272 | } | 3270 | } |
3273 | spin_unlock(&pr_tmpl->registration_lock); | 3271 | spin_unlock(&pr_tmpl->registration_lock); |
3274 | } | 3272 | } |
3275 | spin_unlock(&dev->dev_reservation_lock); | 3273 | spin_unlock(&dev->dev_reservation_lock); |
3276 | /* | 3274 | /* |
3277 | * Call LUN_RESET logic upon list of struct t10_pr_registration, | 3275 | * Call LUN_RESET logic upon list of struct t10_pr_registration, |
3278 | * All received CDBs for the matching existing reservation and | 3276 | * All received CDBs for the matching existing reservation and |
3279 | * registrations undergo ABORT_TASK logic. | 3277 | * registrations undergo ABORT_TASK logic. |
3280 | * | 3278 | * |
3281 | * From there, core_scsi3_release_preempt_and_abort() will | 3279 | * From there, core_scsi3_release_preempt_and_abort() will |
3282 | * release every registration in the list (which have already | 3280 | * release every registration in the list (which have already |
3283 | * been removed from the primary pr_reg list), except the | 3281 | * been removed from the primary pr_reg list), except the |
3284 | * new persistent reservation holder, the calling Initiator Port. | 3282 | * new persistent reservation holder, the calling Initiator Port. |
3285 | */ | 3283 | */ |
3286 | if (abort) { | 3284 | if (abort) { |
3287 | core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd); | 3285 | core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd); |
3288 | core_scsi3_release_preempt_and_abort(&preempt_and_abort_list, | 3286 | core_scsi3_release_preempt_and_abort(&preempt_and_abort_list, |
3289 | pr_reg_n); | 3287 | pr_reg_n); |
3290 | } | 3288 | } |
3291 | 3289 | ||
3292 | if (pr_tmpl->pr_aptpl_active) { | 3290 | if (pr_tmpl->pr_aptpl_active) { |
3293 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, | 3291 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, |
3294 | &pr_reg_n->pr_aptpl_buf[0], | 3292 | &pr_reg_n->pr_aptpl_buf[0], |
3295 | pr_tmpl->pr_aptpl_buf_len); | 3293 | pr_tmpl->pr_aptpl_buf_len); |
3296 | if (!ret) | 3294 | if (!ret) |
3297 | pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT" | 3295 | pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT" |
3298 | "%s\n", (abort) ? "_AND_ABORT" : ""); | 3296 | "%s\n", (abort) ? "_AND_ABORT" : ""); |
3299 | } | 3297 | } |
3300 | 3298 | ||
3301 | core_scsi3_put_pr_reg(pr_reg_n); | 3299 | core_scsi3_put_pr_reg(pr_reg_n); |
3302 | core_scsi3_pr_generation(cmd->se_dev); | 3300 | core_scsi3_pr_generation(cmd->se_dev); |
3303 | return 0; | 3301 | return 0; |
3304 | } | 3302 | } |
3305 | 3303 | ||
3306 | static int core_scsi3_emulate_pro_preempt( | 3304 | static int core_scsi3_emulate_pro_preempt( |
3307 | struct se_cmd *cmd, | 3305 | struct se_cmd *cmd, |
3308 | int type, | 3306 | int type, |
3309 | int scope, | 3307 | int scope, |
3310 | u64 res_key, | 3308 | u64 res_key, |
3311 | u64 sa_res_key, | 3309 | u64 sa_res_key, |
3312 | int abort) | 3310 | int abort) |
3313 | { | 3311 | { |
3314 | int ret = 0; | 3312 | int ret = 0; |
3315 | 3313 | ||
3316 | switch (type) { | 3314 | switch (type) { |
3317 | case PR_TYPE_WRITE_EXCLUSIVE: | 3315 | case PR_TYPE_WRITE_EXCLUSIVE: |
3318 | case PR_TYPE_EXCLUSIVE_ACCESS: | 3316 | case PR_TYPE_EXCLUSIVE_ACCESS: |
3319 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: | 3317 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: |
3320 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: | 3318 | case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: |
3321 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: | 3319 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: |
3322 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: | 3320 | case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: |
3323 | ret = core_scsi3_pro_preempt(cmd, type, scope, | 3321 | ret = core_scsi3_pro_preempt(cmd, type, scope, |
3324 | res_key, sa_res_key, abort); | 3322 | res_key, sa_res_key, abort); |
3325 | break; | 3323 | break; |
3326 | default: | 3324 | default: |
3327 | pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s" | 3325 | pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s" |
3328 | " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); | 3326 | " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); |
3329 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 3327 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
3330 | return -EINVAL; | 3328 | return -EINVAL; |
3331 | } | 3329 | } |
3332 | 3330 | ||
3333 | return ret; | 3331 | return ret; |
3334 | } | 3332 | } |
3335 | 3333 | ||
3336 | 3334 | ||
3337 | static int core_scsi3_emulate_pro_register_and_move( | 3335 | static int core_scsi3_emulate_pro_register_and_move( |
3338 | struct se_cmd *cmd, | 3336 | struct se_cmd *cmd, |
3339 | u64 res_key, | 3337 | u64 res_key, |
3340 | u64 sa_res_key, | 3338 | u64 sa_res_key, |
3341 | int aptpl, | 3339 | int aptpl, |
3342 | int unreg) | 3340 | int unreg) |
3343 | { | 3341 | { |
3344 | struct se_session *se_sess = cmd->se_sess; | 3342 | struct se_session *se_sess = cmd->se_sess; |
3345 | struct se_device *dev = cmd->se_dev; | 3343 | struct se_device *dev = cmd->se_dev; |
3346 | struct se_dev_entry *se_deve, *dest_se_deve = NULL; | 3344 | struct se_dev_entry *se_deve, *dest_se_deve = NULL; |
3347 | struct se_lun *se_lun = cmd->se_lun; | 3345 | struct se_lun *se_lun = cmd->se_lun; |
3348 | struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; | 3346 | struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; |
3349 | struct se_port *se_port; | 3347 | struct se_port *se_port; |
3350 | struct se_portal_group *se_tpg, *dest_se_tpg = NULL; | 3348 | struct se_portal_group *se_tpg, *dest_se_tpg = NULL; |
3351 | struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; | 3349 | struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; |
3352 | struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; | 3350 | struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; |
3353 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 3351 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
3354 | unsigned char *buf; | 3352 | unsigned char *buf; |
3355 | unsigned char *initiator_str; | 3353 | unsigned char *initiator_str; |
3356 | char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; | 3354 | char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; |
3357 | u32 tid_len, tmp_tid_len; | 3355 | u32 tid_len, tmp_tid_len; |
3358 | int new_reg = 0, type, scope, ret, matching_iname, prf_isid; | 3356 | int new_reg = 0, type, scope, ret, matching_iname, prf_isid; |
3359 | unsigned short rtpi; | 3357 | unsigned short rtpi; |
3360 | unsigned char proto_ident; | 3358 | unsigned char proto_ident; |
3361 | 3359 | ||
3362 | if (!se_sess || !se_lun) { | 3360 | if (!se_sess || !se_lun) { |
3363 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); | 3361 | pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); |
3364 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3362 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3365 | return -EINVAL; | 3363 | return -EINVAL; |
3366 | } | 3364 | } |
3367 | memset(dest_iport, 0, 64); | 3365 | memset(dest_iport, 0, 64); |
3368 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 3366 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
3369 | se_tpg = se_sess->se_tpg; | 3367 | se_tpg = se_sess->se_tpg; |
3370 | tf_ops = se_tpg->se_tpg_tfo; | 3368 | tf_ops = se_tpg->se_tpg_tfo; |
3371 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; | 3369 | se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; |
3372 | /* | 3370 | /* |
3373 | * Follow logic from spc4r17 Section 5.7.8, Table 50 -- | 3371 | * Follow logic from spc4r17 Section 5.7.8, Table 50 -- |
3374 | * Register behaviors for a REGISTER AND MOVE service action | 3372 | * Register behaviors for a REGISTER AND MOVE service action |
3375 | * | 3373 | * |
3376 | * Locate the existing *pr_reg via struct se_node_acl pointers | 3374 | * Locate the existing *pr_reg via struct se_node_acl pointers |
3377 | */ | 3375 | */ |
3378 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, | 3376 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, |
3379 | se_sess); | 3377 | se_sess); |
3380 | if (!pr_reg) { | 3378 | if (!pr_reg) { |
3381 | pr_err("SPC-3 PR: Unable to locate PR_REGISTERED" | 3379 | pr_err("SPC-3 PR: Unable to locate PR_REGISTERED" |
3382 | " *pr_reg for REGISTER_AND_MOVE\n"); | 3380 | " *pr_reg for REGISTER_AND_MOVE\n"); |
3383 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3381 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3384 | return -EINVAL; | 3382 | return -EINVAL; |
3385 | } | 3383 | } |
3386 | /* | 3384 | /* |
3387 | * The provided reservation key much match the existing reservation key | 3385 | * The provided reservation key much match the existing reservation key |
3388 | * provided during this initiator's I_T nexus registration. | 3386 | * provided during this initiator's I_T nexus registration. |
3389 | */ | 3387 | */ |
3390 | if (res_key != pr_reg->pr_res_key) { | 3388 | if (res_key != pr_reg->pr_res_key) { |
3391 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received" | 3389 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received" |
3392 | " res_key: 0x%016Lx does not match existing SA REGISTER" | 3390 | " res_key: 0x%016Lx does not match existing SA REGISTER" |
3393 | " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key); | 3391 | " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key); |
3394 | core_scsi3_put_pr_reg(pr_reg); | 3392 | core_scsi3_put_pr_reg(pr_reg); |
3395 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3393 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3396 | return -EINVAL; | 3394 | return -EINVAL; |
3397 | } | 3395 | } |
3398 | /* | 3396 | /* |
3399 | * The service active reservation key needs to be non zero | 3397 | * The service active reservation key needs to be non zero |
3400 | */ | 3398 | */ |
3401 | if (!sa_res_key) { | 3399 | if (!sa_res_key) { |
3402 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received zero" | 3400 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received zero" |
3403 | " sa_res_key\n"); | 3401 | " sa_res_key\n"); |
3404 | core_scsi3_put_pr_reg(pr_reg); | 3402 | core_scsi3_put_pr_reg(pr_reg); |
3405 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3403 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3406 | return -EINVAL; | 3404 | return -EINVAL; |
3407 | } | 3405 | } |
3408 | 3406 | ||
3409 | /* | 3407 | /* |
3410 | * Determine the Relative Target Port Identifier where the reservation | 3408 | * Determine the Relative Target Port Identifier where the reservation |
3411 | * will be moved to for the TransportID containing SCSI initiator WWN | 3409 | * will be moved to for the TransportID containing SCSI initiator WWN |
3412 | * information. | 3410 | * information. |
3413 | */ | 3411 | */ |
3414 | buf = transport_kmap_data_sg(cmd); | 3412 | buf = transport_kmap_data_sg(cmd); |
3415 | rtpi = (buf[18] & 0xff) << 8; | 3413 | rtpi = (buf[18] & 0xff) << 8; |
3416 | rtpi |= buf[19] & 0xff; | 3414 | rtpi |= buf[19] & 0xff; |
3417 | tid_len = (buf[20] & 0xff) << 24; | 3415 | tid_len = (buf[20] & 0xff) << 24; |
3418 | tid_len |= (buf[21] & 0xff) << 16; | 3416 | tid_len |= (buf[21] & 0xff) << 16; |
3419 | tid_len |= (buf[22] & 0xff) << 8; | 3417 | tid_len |= (buf[22] & 0xff) << 8; |
3420 | tid_len |= buf[23] & 0xff; | 3418 | tid_len |= buf[23] & 0xff; |
3421 | transport_kunmap_data_sg(cmd); | 3419 | transport_kunmap_data_sg(cmd); |
3422 | buf = NULL; | 3420 | buf = NULL; |
3423 | 3421 | ||
3424 | if ((tid_len + 24) != cmd->data_length) { | 3422 | if ((tid_len + 24) != cmd->data_length) { |
3425 | pr_err("SPC-3 PR: Illegal tid_len: %u + 24 byte header" | 3423 | pr_err("SPC-3 PR: Illegal tid_len: %u + 24 byte header" |
3426 | " does not equal CDB data_length: %u\n", tid_len, | 3424 | " does not equal CDB data_length: %u\n", tid_len, |
3427 | cmd->data_length); | 3425 | cmd->data_length); |
3428 | core_scsi3_put_pr_reg(pr_reg); | 3426 | core_scsi3_put_pr_reg(pr_reg); |
3429 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3427 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3430 | return -EINVAL; | 3428 | return -EINVAL; |
3431 | } | 3429 | } |
3432 | 3430 | ||
3433 | spin_lock(&dev->se_port_lock); | 3431 | spin_lock(&dev->se_port_lock); |
3434 | list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) { | 3432 | list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) { |
3435 | if (se_port->sep_rtpi != rtpi) | 3433 | if (se_port->sep_rtpi != rtpi) |
3436 | continue; | 3434 | continue; |
3437 | dest_se_tpg = se_port->sep_tpg; | 3435 | dest_se_tpg = se_port->sep_tpg; |
3438 | if (!dest_se_tpg) | 3436 | if (!dest_se_tpg) |
3439 | continue; | 3437 | continue; |
3440 | dest_tf_ops = dest_se_tpg->se_tpg_tfo; | 3438 | dest_tf_ops = dest_se_tpg->se_tpg_tfo; |
3441 | if (!dest_tf_ops) | 3439 | if (!dest_tf_ops) |
3442 | continue; | 3440 | continue; |
3443 | 3441 | ||
3444 | atomic_inc(&dest_se_tpg->tpg_pr_ref_count); | 3442 | atomic_inc(&dest_se_tpg->tpg_pr_ref_count); |
3445 | smp_mb__after_atomic_inc(); | 3443 | smp_mb__after_atomic_inc(); |
3446 | spin_unlock(&dev->se_port_lock); | 3444 | spin_unlock(&dev->se_port_lock); |
3447 | 3445 | ||
3448 | ret = core_scsi3_tpg_depend_item(dest_se_tpg); | 3446 | ret = core_scsi3_tpg_depend_item(dest_se_tpg); |
3449 | if (ret != 0) { | 3447 | if (ret != 0) { |
3450 | pr_err("core_scsi3_tpg_depend_item() failed" | 3448 | pr_err("core_scsi3_tpg_depend_item() failed" |
3451 | " for dest_se_tpg\n"); | 3449 | " for dest_se_tpg\n"); |
3452 | atomic_dec(&dest_se_tpg->tpg_pr_ref_count); | 3450 | atomic_dec(&dest_se_tpg->tpg_pr_ref_count); |
3453 | smp_mb__after_atomic_dec(); | 3451 | smp_mb__after_atomic_dec(); |
3454 | core_scsi3_put_pr_reg(pr_reg); | 3452 | core_scsi3_put_pr_reg(pr_reg); |
3455 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3453 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3456 | return -EINVAL; | 3454 | return -EINVAL; |
3457 | } | 3455 | } |
3458 | 3456 | ||
3459 | spin_lock(&dev->se_port_lock); | 3457 | spin_lock(&dev->se_port_lock); |
3460 | break; | 3458 | break; |
3461 | } | 3459 | } |
3462 | spin_unlock(&dev->se_port_lock); | 3460 | spin_unlock(&dev->se_port_lock); |
3463 | 3461 | ||
3464 | if (!dest_se_tpg || !dest_tf_ops) { | 3462 | if (!dest_se_tpg || !dest_tf_ops) { |
3465 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" | 3463 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" |
3466 | " fabric ops from Relative Target Port Identifier:" | 3464 | " fabric ops from Relative Target Port Identifier:" |
3467 | " %hu\n", rtpi); | 3465 | " %hu\n", rtpi); |
3468 | core_scsi3_put_pr_reg(pr_reg); | 3466 | core_scsi3_put_pr_reg(pr_reg); |
3469 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3467 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3470 | return -EINVAL; | 3468 | return -EINVAL; |
3471 | } | 3469 | } |
3472 | 3470 | ||
3473 | buf = transport_kmap_data_sg(cmd); | 3471 | buf = transport_kmap_data_sg(cmd); |
3474 | proto_ident = (buf[24] & 0x0f); | 3472 | proto_ident = (buf[24] & 0x0f); |
3475 | #if 0 | 3473 | #if 0 |
3476 | pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" | 3474 | pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" |
3477 | " 0x%02x\n", proto_ident); | 3475 | " 0x%02x\n", proto_ident); |
3478 | #endif | 3476 | #endif |
3479 | if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) { | 3477 | if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) { |
3480 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Received" | 3478 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Received" |
3481 | " proto_ident: 0x%02x does not match ident: 0x%02x" | 3479 | " proto_ident: 0x%02x does not match ident: 0x%02x" |
3482 | " from fabric: %s\n", proto_ident, | 3480 | " from fabric: %s\n", proto_ident, |
3483 | dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), | 3481 | dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), |
3484 | dest_tf_ops->get_fabric_name()); | 3482 | dest_tf_ops->get_fabric_name()); |
3485 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3483 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3486 | ret = -EINVAL; | 3484 | ret = -EINVAL; |
3487 | goto out; | 3485 | goto out; |
3488 | } | 3486 | } |
3489 | if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { | 3487 | if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { |
3490 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not" | 3488 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not" |
3491 | " containg a valid tpg_parse_pr_out_transport_id" | 3489 | " containg a valid tpg_parse_pr_out_transport_id" |
3492 | " function pointer\n"); | 3490 | " function pointer\n"); |
3493 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3491 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3494 | ret = -EINVAL; | 3492 | ret = -EINVAL; |
3495 | goto out; | 3493 | goto out; |
3496 | } | 3494 | } |
3497 | initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, | 3495 | initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, |
3498 | (const char *)&buf[24], &tmp_tid_len, &iport_ptr); | 3496 | (const char *)&buf[24], &tmp_tid_len, &iport_ptr); |
3499 | if (!initiator_str) { | 3497 | if (!initiator_str) { |
3500 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" | 3498 | pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" |
3501 | " initiator_str from Transport ID\n"); | 3499 | " initiator_str from Transport ID\n"); |
3502 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3500 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3503 | ret = -EINVAL; | 3501 | ret = -EINVAL; |
3504 | goto out; | 3502 | goto out; |
3505 | } | 3503 | } |
3506 | 3504 | ||
3507 | transport_kunmap_data_sg(cmd); | 3505 | transport_kunmap_data_sg(cmd); |
3508 | buf = NULL; | 3506 | buf = NULL; |
3509 | 3507 | ||
3510 | pr_debug("SPC-3 PR [%s] Extracted initiator %s identifier: %s" | 3508 | pr_debug("SPC-3 PR [%s] Extracted initiator %s identifier: %s" |
3511 | " %s\n", dest_tf_ops->get_fabric_name(), (iport_ptr != NULL) ? | 3509 | " %s\n", dest_tf_ops->get_fabric_name(), (iport_ptr != NULL) ? |
3512 | "port" : "device", initiator_str, (iport_ptr != NULL) ? | 3510 | "port" : "device", initiator_str, (iport_ptr != NULL) ? |
3513 | iport_ptr : ""); | 3511 | iport_ptr : ""); |
3514 | /* | 3512 | /* |
3515 | * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service | 3513 | * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service |
3516 | * action specifies a TransportID that is the same as the initiator port | 3514 | * action specifies a TransportID that is the same as the initiator port |
3517 | * of the I_T nexus for the command received, then the command shall | 3515 | * of the I_T nexus for the command received, then the command shall |
3518 | * be terminated with CHECK CONDITION status, with the sense key set to | 3516 | * be terminated with CHECK CONDITION status, with the sense key set to |
3519 | * ILLEGAL REQUEST, and the additional sense code set to INVALID FIELD | 3517 | * ILLEGAL REQUEST, and the additional sense code set to INVALID FIELD |
3520 | * IN PARAMETER LIST. | 3518 | * IN PARAMETER LIST. |
3521 | */ | 3519 | */ |
3522 | pr_reg_nacl = pr_reg->pr_reg_nacl; | 3520 | pr_reg_nacl = pr_reg->pr_reg_nacl; |
3523 | matching_iname = (!strcmp(initiator_str, | 3521 | matching_iname = (!strcmp(initiator_str, |
3524 | pr_reg_nacl->initiatorname)) ? 1 : 0; | 3522 | pr_reg_nacl->initiatorname)) ? 1 : 0; |
3525 | if (!matching_iname) | 3523 | if (!matching_iname) |
3526 | goto after_iport_check; | 3524 | goto after_iport_check; |
3527 | 3525 | ||
3528 | if (!iport_ptr || !pr_reg->isid_present_at_reg) { | 3526 | if (!iport_ptr || !pr_reg->isid_present_at_reg) { |
3529 | pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s" | 3527 | pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s" |
3530 | " matches: %s on received I_T Nexus\n", initiator_str, | 3528 | " matches: %s on received I_T Nexus\n", initiator_str, |
3531 | pr_reg_nacl->initiatorname); | 3529 | pr_reg_nacl->initiatorname); |
3532 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3530 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3533 | ret = -EINVAL; | 3531 | ret = -EINVAL; |
3534 | goto out; | 3532 | goto out; |
3535 | } | 3533 | } |
3536 | if (!strcmp(iport_ptr, pr_reg->pr_reg_isid)) { | 3534 | if (!strcmp(iport_ptr, pr_reg->pr_reg_isid)) { |
3537 | pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s %s" | 3535 | pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s %s" |
3538 | " matches: %s %s on received I_T Nexus\n", | 3536 | " matches: %s %s on received I_T Nexus\n", |
3539 | initiator_str, iport_ptr, pr_reg_nacl->initiatorname, | 3537 | initiator_str, iport_ptr, pr_reg_nacl->initiatorname, |
3540 | pr_reg->pr_reg_isid); | 3538 | pr_reg->pr_reg_isid); |
3541 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3539 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3542 | ret = -EINVAL; | 3540 | ret = -EINVAL; |
3543 | goto out; | 3541 | goto out; |
3544 | } | 3542 | } |
3545 | after_iport_check: | 3543 | after_iport_check: |
3546 | /* | 3544 | /* |
3547 | * Locate the destination struct se_node_acl from the received Transport ID | 3545 | * Locate the destination struct se_node_acl from the received Transport ID |
3548 | */ | 3546 | */ |
3549 | spin_lock_irq(&dest_se_tpg->acl_node_lock); | 3547 | spin_lock_irq(&dest_se_tpg->acl_node_lock); |
3550 | dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg, | 3548 | dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg, |
3551 | initiator_str); | 3549 | initiator_str); |
3552 | if (dest_node_acl) { | 3550 | if (dest_node_acl) { |
3553 | atomic_inc(&dest_node_acl->acl_pr_ref_count); | 3551 | atomic_inc(&dest_node_acl->acl_pr_ref_count); |
3554 | smp_mb__after_atomic_inc(); | 3552 | smp_mb__after_atomic_inc(); |
3555 | } | 3553 | } |
3556 | spin_unlock_irq(&dest_se_tpg->acl_node_lock); | 3554 | spin_unlock_irq(&dest_se_tpg->acl_node_lock); |
3557 | 3555 | ||
3558 | if (!dest_node_acl) { | 3556 | if (!dest_node_acl) { |
3559 | pr_err("Unable to locate %s dest_node_acl for" | 3557 | pr_err("Unable to locate %s dest_node_acl for" |
3560 | " TransportID%s\n", dest_tf_ops->get_fabric_name(), | 3558 | " TransportID%s\n", dest_tf_ops->get_fabric_name(), |
3561 | initiator_str); | 3559 | initiator_str); |
3562 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3560 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3563 | ret = -EINVAL; | 3561 | ret = -EINVAL; |
3564 | goto out; | 3562 | goto out; |
3565 | } | 3563 | } |
3566 | ret = core_scsi3_nodeacl_depend_item(dest_node_acl); | 3564 | ret = core_scsi3_nodeacl_depend_item(dest_node_acl); |
3567 | if (ret != 0) { | 3565 | if (ret != 0) { |
3568 | pr_err("core_scsi3_nodeacl_depend_item() for" | 3566 | pr_err("core_scsi3_nodeacl_depend_item() for" |
3569 | " dest_node_acl\n"); | 3567 | " dest_node_acl\n"); |
3570 | atomic_dec(&dest_node_acl->acl_pr_ref_count); | 3568 | atomic_dec(&dest_node_acl->acl_pr_ref_count); |
3571 | smp_mb__after_atomic_dec(); | 3569 | smp_mb__after_atomic_dec(); |
3572 | dest_node_acl = NULL; | 3570 | dest_node_acl = NULL; |
3573 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3571 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3574 | ret = -EINVAL; | 3572 | ret = -EINVAL; |
3575 | goto out; | 3573 | goto out; |
3576 | } | 3574 | } |
3577 | #if 0 | 3575 | #if 0 |
3578 | pr_debug("SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:" | 3576 | pr_debug("SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:" |
3579 | " %s from TransportID\n", dest_tf_ops->get_fabric_name(), | 3577 | " %s from TransportID\n", dest_tf_ops->get_fabric_name(), |
3580 | dest_node_acl->initiatorname); | 3578 | dest_node_acl->initiatorname); |
3581 | #endif | 3579 | #endif |
3582 | /* | 3580 | /* |
3583 | * Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET | 3581 | * Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET |
3584 | * PORT IDENTIFIER. | 3582 | * PORT IDENTIFIER. |
3585 | */ | 3583 | */ |
3586 | dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, rtpi); | 3584 | dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, rtpi); |
3587 | if (!dest_se_deve) { | 3585 | if (!dest_se_deve) { |
3588 | pr_err("Unable to locate %s dest_se_deve from RTPI:" | 3586 | pr_err("Unable to locate %s dest_se_deve from RTPI:" |
3589 | " %hu\n", dest_tf_ops->get_fabric_name(), rtpi); | 3587 | " %hu\n", dest_tf_ops->get_fabric_name(), rtpi); |
3590 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3588 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3591 | ret = -EINVAL; | 3589 | ret = -EINVAL; |
3592 | goto out; | 3590 | goto out; |
3593 | } | 3591 | } |
3594 | 3592 | ||
3595 | ret = core_scsi3_lunacl_depend_item(dest_se_deve); | 3593 | ret = core_scsi3_lunacl_depend_item(dest_se_deve); |
3596 | if (ret < 0) { | 3594 | if (ret < 0) { |
3597 | pr_err("core_scsi3_lunacl_depend_item() failed\n"); | 3595 | pr_err("core_scsi3_lunacl_depend_item() failed\n"); |
3598 | atomic_dec(&dest_se_deve->pr_ref_count); | 3596 | atomic_dec(&dest_se_deve->pr_ref_count); |
3599 | smp_mb__after_atomic_dec(); | 3597 | smp_mb__after_atomic_dec(); |
3600 | dest_se_deve = NULL; | 3598 | dest_se_deve = NULL; |
3601 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3599 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3602 | ret = -EINVAL; | 3600 | ret = -EINVAL; |
3603 | goto out; | 3601 | goto out; |
3604 | } | 3602 | } |
3605 | #if 0 | 3603 | #if 0 |
3606 | pr_debug("SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN" | 3604 | pr_debug("SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN" |
3607 | " ACL for dest_se_deve->mapped_lun: %u\n", | 3605 | " ACL for dest_se_deve->mapped_lun: %u\n", |
3608 | dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname, | 3606 | dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname, |
3609 | dest_se_deve->mapped_lun); | 3607 | dest_se_deve->mapped_lun); |
3610 | #endif | 3608 | #endif |
3611 | /* | 3609 | /* |
3612 | * A persistent reservation needs to already existing in order to | 3610 | * A persistent reservation needs to already existing in order to |
3613 | * successfully complete the REGISTER_AND_MOVE service action.. | 3611 | * successfully complete the REGISTER_AND_MOVE service action.. |
3614 | */ | 3612 | */ |
3615 | spin_lock(&dev->dev_reservation_lock); | 3613 | spin_lock(&dev->dev_reservation_lock); |
3616 | pr_res_holder = dev->dev_pr_res_holder; | 3614 | pr_res_holder = dev->dev_pr_res_holder; |
3617 | if (!pr_res_holder) { | 3615 | if (!pr_res_holder) { |
3618 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: No reservation" | 3616 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: No reservation" |
3619 | " currently held\n"); | 3617 | " currently held\n"); |
3620 | spin_unlock(&dev->dev_reservation_lock); | 3618 | spin_unlock(&dev->dev_reservation_lock); |
3621 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 3619 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
3622 | ret = -EINVAL; | 3620 | ret = -EINVAL; |
3623 | goto out; | 3621 | goto out; |
3624 | } | 3622 | } |
3625 | /* | 3623 | /* |
3626 | * The received on I_T Nexus must be the reservation holder. | 3624 | * The received on I_T Nexus must be the reservation holder. |
3627 | * | 3625 | * |
3628 | * From spc4r17 section 5.7.8 Table 50 -- | 3626 | * From spc4r17 section 5.7.8 Table 50 -- |
3629 | * Register behaviors for a REGISTER AND MOVE service action | 3627 | * Register behaviors for a REGISTER AND MOVE service action |
3630 | */ | 3628 | */ |
3631 | if (pr_res_holder != pr_reg) { | 3629 | if (pr_res_holder != pr_reg) { |
3632 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T" | 3630 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T" |
3633 | " Nexus is not reservation holder\n"); | 3631 | " Nexus is not reservation holder\n"); |
3634 | spin_unlock(&dev->dev_reservation_lock); | 3632 | spin_unlock(&dev->dev_reservation_lock); |
3635 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3633 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3636 | ret = -EINVAL; | 3634 | ret = -EINVAL; |
3637 | goto out; | 3635 | goto out; |
3638 | } | 3636 | } |
3639 | /* | 3637 | /* |
3640 | * From spc4r17 section 5.7.8: registering and moving reservation | 3638 | * From spc4r17 section 5.7.8: registering and moving reservation |
3641 | * | 3639 | * |
3642 | * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service | 3640 | * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service |
3643 | * action is received and the established persistent reservation is a | 3641 | * action is received and the established persistent reservation is a |
3644 | * Write Exclusive - All Registrants type or Exclusive Access - | 3642 | * Write Exclusive - All Registrants type or Exclusive Access - |
3645 | * All Registrants type reservation, then the command shall be completed | 3643 | * All Registrants type reservation, then the command shall be completed |
3646 | * with RESERVATION CONFLICT status. | 3644 | * with RESERVATION CONFLICT status. |
3647 | */ | 3645 | */ |
3648 | if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | 3646 | if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || |
3649 | (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { | 3647 | (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { |
3650 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Unable to move" | 3648 | pr_warn("SPC-3 PR REGISTER_AND_MOVE: Unable to move" |
3651 | " reservation for type: %s\n", | 3649 | " reservation for type: %s\n", |
3652 | core_scsi3_pr_dump_type(pr_res_holder->pr_res_type)); | 3650 | core_scsi3_pr_dump_type(pr_res_holder->pr_res_type)); |
3653 | spin_unlock(&dev->dev_reservation_lock); | 3651 | spin_unlock(&dev->dev_reservation_lock); |
3654 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3652 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3655 | ret = -EINVAL; | 3653 | ret = -EINVAL; |
3656 | goto out; | 3654 | goto out; |
3657 | } | 3655 | } |
3658 | pr_res_nacl = pr_res_holder->pr_reg_nacl; | 3656 | pr_res_nacl = pr_res_holder->pr_reg_nacl; |
3659 | /* | 3657 | /* |
3660 | * b) Ignore the contents of the (received) SCOPE and TYPE fields; | 3658 | * b) Ignore the contents of the (received) SCOPE and TYPE fields; |
3661 | */ | 3659 | */ |
3662 | type = pr_res_holder->pr_res_type; | 3660 | type = pr_res_holder->pr_res_type; |
3663 | scope = pr_res_holder->pr_res_type; | 3661 | scope = pr_res_holder->pr_res_type; |
3664 | /* | 3662 | /* |
3665 | * c) Associate the reservation key specified in the SERVICE ACTION | 3663 | * c) Associate the reservation key specified in the SERVICE ACTION |
3666 | * RESERVATION KEY field with the I_T nexus specified as the | 3664 | * RESERVATION KEY field with the I_T nexus specified as the |
3667 | * destination of the register and move, where: | 3665 | * destination of the register and move, where: |
3668 | * A) The I_T nexus is specified by the TransportID and the | 3666 | * A) The I_T nexus is specified by the TransportID and the |
3669 | * RELATIVE TARGET PORT IDENTIFIER field (see 6.14.4); and | 3667 | * RELATIVE TARGET PORT IDENTIFIER field (see 6.14.4); and |
3670 | * B) Regardless of the TransportID format used, the association for | 3668 | * B) Regardless of the TransportID format used, the association for |
3671 | * the initiator port is based on either the initiator port name | 3669 | * the initiator port is based on either the initiator port name |
3672 | * (see 3.1.71) on SCSI transport protocols where port names are | 3670 | * (see 3.1.71) on SCSI transport protocols where port names are |
3673 | * required or the initiator port identifier (see 3.1.70) on SCSI | 3671 | * required or the initiator port identifier (see 3.1.70) on SCSI |
3674 | * transport protocols where port names are not required; | 3672 | * transport protocols where port names are not required; |
3675 | * d) Register the reservation key specified in the SERVICE ACTION | 3673 | * d) Register the reservation key specified in the SERVICE ACTION |
3676 | * RESERVATION KEY field; | 3674 | * RESERVATION KEY field; |
3677 | * e) Retain the reservation key specified in the SERVICE ACTION | 3675 | * e) Retain the reservation key specified in the SERVICE ACTION |
3678 | * RESERVATION KEY field and associated information; | 3676 | * RESERVATION KEY field and associated information; |
3679 | * | 3677 | * |
3680 | * Also, It is not an error for a REGISTER AND MOVE service action to | 3678 | * Also, It is not an error for a REGISTER AND MOVE service action to |
3681 | * register an I_T nexus that is already registered with the same | 3679 | * register an I_T nexus that is already registered with the same |
3682 | * reservation key or a different reservation key. | 3680 | * reservation key or a different reservation key. |
3683 | */ | 3681 | */ |
3684 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, | 3682 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, |
3685 | iport_ptr); | 3683 | iport_ptr); |
3686 | if (!dest_pr_reg) { | 3684 | if (!dest_pr_reg) { |
3687 | ret = core_scsi3_alloc_registration(cmd->se_dev, | 3685 | ret = core_scsi3_alloc_registration(cmd->se_dev, |
3688 | dest_node_acl, dest_se_deve, iport_ptr, | 3686 | dest_node_acl, dest_se_deve, iport_ptr, |
3689 | sa_res_key, 0, aptpl, 2, 1); | 3687 | sa_res_key, 0, aptpl, 2, 1); |
3690 | if (ret != 0) { | 3688 | if (ret != 0) { |
3691 | spin_unlock(&dev->dev_reservation_lock); | 3689 | spin_unlock(&dev->dev_reservation_lock); |
3692 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3690 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3693 | ret = -EINVAL; | 3691 | ret = -EINVAL; |
3694 | goto out; | 3692 | goto out; |
3695 | } | 3693 | } |
3696 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, | 3694 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, |
3697 | iport_ptr); | 3695 | iport_ptr); |
3698 | new_reg = 1; | 3696 | new_reg = 1; |
3699 | } | 3697 | } |
3700 | /* | 3698 | /* |
3701 | * f) Release the persistent reservation for the persistent reservation | 3699 | * f) Release the persistent reservation for the persistent reservation |
3702 | * holder (i.e., the I_T nexus on which the | 3700 | * holder (i.e., the I_T nexus on which the |
3703 | */ | 3701 | */ |
3704 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, | 3702 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, |
3705 | dev->dev_pr_res_holder, 0); | 3703 | dev->dev_pr_res_holder, 0); |
3706 | /* | 3704 | /* |
3707 | * g) Move the persistent reservation to the specified I_T nexus using | 3705 | * g) Move the persistent reservation to the specified I_T nexus using |
3708 | * the same scope and type as the persistent reservation released in | 3706 | * the same scope and type as the persistent reservation released in |
3709 | * item f); and | 3707 | * item f); and |
3710 | */ | 3708 | */ |
3711 | dev->dev_pr_res_holder = dest_pr_reg; | 3709 | dev->dev_pr_res_holder = dest_pr_reg; |
3712 | dest_pr_reg->pr_res_holder = 1; | 3710 | dest_pr_reg->pr_res_holder = 1; |
3713 | dest_pr_reg->pr_res_type = type; | 3711 | dest_pr_reg->pr_res_type = type; |
3714 | pr_reg->pr_res_scope = scope; | 3712 | pr_reg->pr_res_scope = scope; |
3715 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], | 3713 | prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], |
3716 | PR_REG_ISID_ID_LEN); | 3714 | PR_REG_ISID_ID_LEN); |
3717 | /* | 3715 | /* |
3718 | * Increment PRGeneration for existing registrations.. | 3716 | * Increment PRGeneration for existing registrations.. |
3719 | */ | 3717 | */ |
3720 | if (!new_reg) | 3718 | if (!new_reg) |
3721 | dest_pr_reg->pr_res_generation = pr_tmpl->pr_generation++; | 3719 | dest_pr_reg->pr_res_generation = pr_tmpl->pr_generation++; |
3722 | spin_unlock(&dev->dev_reservation_lock); | 3720 | spin_unlock(&dev->dev_reservation_lock); |
3723 | 3721 | ||
3724 | pr_debug("SPC-3 PR [%s] Service Action: REGISTER_AND_MOVE" | 3722 | pr_debug("SPC-3 PR [%s] Service Action: REGISTER_AND_MOVE" |
3725 | " created new reservation holder TYPE: %s on object RTPI:" | 3723 | " created new reservation holder TYPE: %s on object RTPI:" |
3726 | " %hu PRGeneration: 0x%08x\n", dest_tf_ops->get_fabric_name(), | 3724 | " %hu PRGeneration: 0x%08x\n", dest_tf_ops->get_fabric_name(), |
3727 | core_scsi3_pr_dump_type(type), rtpi, | 3725 | core_scsi3_pr_dump_type(type), rtpi, |
3728 | dest_pr_reg->pr_res_generation); | 3726 | dest_pr_reg->pr_res_generation); |
3729 | pr_debug("SPC-3 PR Successfully moved reservation from" | 3727 | pr_debug("SPC-3 PR Successfully moved reservation from" |
3730 | " %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n", | 3728 | " %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n", |
3731 | tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname, | 3729 | tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname, |
3732 | (prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(), | 3730 | (prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(), |
3733 | dest_node_acl->initiatorname, (iport_ptr != NULL) ? | 3731 | dest_node_acl->initiatorname, (iport_ptr != NULL) ? |
3734 | iport_ptr : ""); | 3732 | iport_ptr : ""); |
3735 | /* | 3733 | /* |
3736 | * It is now safe to release configfs group dependencies for destination | 3734 | * It is now safe to release configfs group dependencies for destination |
3737 | * of Transport ID Initiator Device/Port Identifier | 3735 | * of Transport ID Initiator Device/Port Identifier |
3738 | */ | 3736 | */ |
3739 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 3737 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
3740 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 3738 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
3741 | core_scsi3_tpg_undepend_item(dest_se_tpg); | 3739 | core_scsi3_tpg_undepend_item(dest_se_tpg); |
3742 | /* | 3740 | /* |
3743 | * h) If the UNREG bit is set to one, unregister (see 5.7.11.3) the I_T | 3741 | * h) If the UNREG bit is set to one, unregister (see 5.7.11.3) the I_T |
3744 | * nexus on which PERSISTENT RESERVE OUT command was received. | 3742 | * nexus on which PERSISTENT RESERVE OUT command was received. |
3745 | */ | 3743 | */ |
3746 | if (unreg) { | 3744 | if (unreg) { |
3747 | spin_lock(&pr_tmpl->registration_lock); | 3745 | spin_lock(&pr_tmpl->registration_lock); |
3748 | __core_scsi3_free_registration(dev, pr_reg, NULL, 1); | 3746 | __core_scsi3_free_registration(dev, pr_reg, NULL, 1); |
3749 | spin_unlock(&pr_tmpl->registration_lock); | 3747 | spin_unlock(&pr_tmpl->registration_lock); |
3750 | } else | 3748 | } else |
3751 | core_scsi3_put_pr_reg(pr_reg); | 3749 | core_scsi3_put_pr_reg(pr_reg); |
3752 | 3750 | ||
3753 | /* | 3751 | /* |
3754 | * Clear the APTPL metadata if APTPL has been disabled, otherwise | 3752 | * Clear the APTPL metadata if APTPL has been disabled, otherwise |
3755 | * write out the updated metadata to struct file for this SCSI device. | 3753 | * write out the updated metadata to struct file for this SCSI device. |
3756 | */ | 3754 | */ |
3757 | if (!aptpl) { | 3755 | if (!aptpl) { |
3758 | pr_tmpl->pr_aptpl_active = 0; | 3756 | pr_tmpl->pr_aptpl_active = 0; |
3759 | core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); | 3757 | core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); |
3760 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for" | 3758 | pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for" |
3761 | " REGISTER_AND_MOVE\n"); | 3759 | " REGISTER_AND_MOVE\n"); |
3762 | } else { | 3760 | } else { |
3763 | pr_tmpl->pr_aptpl_active = 1; | 3761 | pr_tmpl->pr_aptpl_active = 1; |
3764 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, | 3762 | ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, |
3765 | &dest_pr_reg->pr_aptpl_buf[0], | 3763 | &dest_pr_reg->pr_aptpl_buf[0], |
3766 | pr_tmpl->pr_aptpl_buf_len); | 3764 | pr_tmpl->pr_aptpl_buf_len); |
3767 | if (!ret) | 3765 | if (!ret) |
3768 | pr_debug("SPC-3 PR: Set APTPL Bit Activated for" | 3766 | pr_debug("SPC-3 PR: Set APTPL Bit Activated for" |
3769 | " REGISTER_AND_MOVE\n"); | 3767 | " REGISTER_AND_MOVE\n"); |
3770 | } | 3768 | } |
3771 | 3769 | ||
3772 | transport_kunmap_data_sg(cmd); | 3770 | transport_kunmap_data_sg(cmd); |
3773 | 3771 | ||
3774 | core_scsi3_put_pr_reg(dest_pr_reg); | 3772 | core_scsi3_put_pr_reg(dest_pr_reg); |
3775 | return 0; | 3773 | return 0; |
3776 | out: | 3774 | out: |
3777 | if (buf) | 3775 | if (buf) |
3778 | transport_kunmap_data_sg(cmd); | 3776 | transport_kunmap_data_sg(cmd); |
3779 | if (dest_se_deve) | 3777 | if (dest_se_deve) |
3780 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 3778 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
3781 | if (dest_node_acl) | 3779 | if (dest_node_acl) |
3782 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 3780 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
3783 | core_scsi3_tpg_undepend_item(dest_se_tpg); | 3781 | core_scsi3_tpg_undepend_item(dest_se_tpg); |
3784 | core_scsi3_put_pr_reg(pr_reg); | 3782 | core_scsi3_put_pr_reg(pr_reg); |
3785 | return ret; | 3783 | return ret; |
3786 | } | 3784 | } |
3787 | 3785 | ||
3788 | static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) | 3786 | static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) |
3789 | { | 3787 | { |
3790 | unsigned int __v1, __v2; | 3788 | unsigned int __v1, __v2; |
3791 | 3789 | ||
3792 | __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3]; | 3790 | __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3]; |
3793 | __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7]; | 3791 | __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7]; |
3794 | 3792 | ||
3795 | return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; | 3793 | return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; |
3796 | } | 3794 | } |
3797 | 3795 | ||
3798 | /* | 3796 | /* |
3799 | * See spc4r17 section 6.14 Table 170 | 3797 | * See spc4r17 section 6.14 Table 170 |
3800 | */ | 3798 | */ |
3801 | int target_scsi3_emulate_pr_out(struct se_task *task) | 3799 | int target_scsi3_emulate_pr_out(struct se_task *task) |
3802 | { | 3800 | { |
3803 | struct se_cmd *cmd = task->task_se_cmd; | 3801 | struct se_cmd *cmd = task->task_se_cmd; |
3804 | unsigned char *cdb = &cmd->t_task_cdb[0]; | 3802 | unsigned char *cdb = &cmd->t_task_cdb[0]; |
3805 | unsigned char *buf; | 3803 | unsigned char *buf; |
3806 | u64 res_key, sa_res_key; | 3804 | u64 res_key, sa_res_key; |
3807 | int sa, scope, type, aptpl; | 3805 | int sa, scope, type, aptpl; |
3808 | int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; | 3806 | int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; |
3809 | int ret; | 3807 | int ret; |
3810 | 3808 | ||
3811 | /* | 3809 | /* |
3812 | * Following spc2r20 5.5.1 Reservations overview: | 3810 | * Following spc2r20 5.5.1 Reservations overview: |
3813 | * | 3811 | * |
3814 | * If a logical unit has been reserved by any RESERVE command and is | 3812 | * If a logical unit has been reserved by any RESERVE command and is |
3815 | * still reserved by any initiator, all PERSISTENT RESERVE IN and all | 3813 | * still reserved by any initiator, all PERSISTENT RESERVE IN and all |
3816 | * PERSISTENT RESERVE OUT commands shall conflict regardless of | 3814 | * PERSISTENT RESERVE OUT commands shall conflict regardless of |
3817 | * initiator or service action and shall terminate with a RESERVATION | 3815 | * initiator or service action and shall terminate with a RESERVATION |
3818 | * CONFLICT status. | 3816 | * CONFLICT status. |
3819 | */ | 3817 | */ |
3820 | if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { | 3818 | if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { |
3821 | pr_err("Received PERSISTENT_RESERVE CDB while legacy" | 3819 | pr_err("Received PERSISTENT_RESERVE CDB while legacy" |
3822 | " SPC-2 reservation is held, returning" | 3820 | " SPC-2 reservation is held, returning" |
3823 | " RESERVATION_CONFLICT\n"); | 3821 | " RESERVATION_CONFLICT\n"); |
3824 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 3822 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
3825 | ret = EINVAL; | 3823 | ret = EINVAL; |
3826 | goto out; | 3824 | goto out; |
3827 | } | 3825 | } |
3828 | 3826 | ||
3829 | /* | 3827 | /* |
3830 | * FIXME: A NULL struct se_session pointer means an this is not coming from | 3828 | * FIXME: A NULL struct se_session pointer means an this is not coming from |
3831 | * a $FABRIC_MOD's nexus, but from internal passthrough ops. | 3829 | * a $FABRIC_MOD's nexus, but from internal passthrough ops. |
3832 | */ | 3830 | */ |
3833 | if (!cmd->se_sess) { | 3831 | if (!cmd->se_sess) { |
3834 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 3832 | cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
3835 | return -EINVAL; | 3833 | return -EINVAL; |
3836 | } | 3834 | } |
3837 | 3835 | ||
3838 | if (cmd->data_length < 24) { | 3836 | if (cmd->data_length < 24) { |
3839 | pr_warn("SPC-PR: Received PR OUT parameter list" | 3837 | pr_warn("SPC-PR: Received PR OUT parameter list" |
3840 | " length too small: %u\n", cmd->data_length); | 3838 | " length too small: %u\n", cmd->data_length); |
3841 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3839 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3842 | ret = -EINVAL; | 3840 | ret = -EINVAL; |
3843 | goto out; | 3841 | goto out; |
3844 | } | 3842 | } |
3845 | /* | 3843 | /* |
3846 | * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) | 3844 | * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) |
3847 | */ | 3845 | */ |
3848 | sa = (cdb[1] & 0x1f); | 3846 | sa = (cdb[1] & 0x1f); |
3849 | scope = (cdb[2] & 0xf0); | 3847 | scope = (cdb[2] & 0xf0); |
3850 | type = (cdb[2] & 0x0f); | 3848 | type = (cdb[2] & 0x0f); |
3851 | 3849 | ||
3852 | buf = transport_kmap_data_sg(cmd); | 3850 | buf = transport_kmap_data_sg(cmd); |
3853 | /* | 3851 | /* |
3854 | * From PERSISTENT_RESERVE_OUT parameter list (payload) | 3852 | * From PERSISTENT_RESERVE_OUT parameter list (payload) |
3855 | */ | 3853 | */ |
3856 | res_key = core_scsi3_extract_reservation_key(&buf[0]); | 3854 | res_key = core_scsi3_extract_reservation_key(&buf[0]); |
3857 | sa_res_key = core_scsi3_extract_reservation_key(&buf[8]); | 3855 | sa_res_key = core_scsi3_extract_reservation_key(&buf[8]); |
3858 | /* | 3856 | /* |
3859 | * REGISTER_AND_MOVE uses a different SA parameter list containing | 3857 | * REGISTER_AND_MOVE uses a different SA parameter list containing |
3860 | * SCSI TransportIDs. | 3858 | * SCSI TransportIDs. |
3861 | */ | 3859 | */ |
3862 | if (sa != PRO_REGISTER_AND_MOVE) { | 3860 | if (sa != PRO_REGISTER_AND_MOVE) { |
3863 | spec_i_pt = (buf[20] & 0x08); | 3861 | spec_i_pt = (buf[20] & 0x08); |
3864 | all_tg_pt = (buf[20] & 0x04); | 3862 | all_tg_pt = (buf[20] & 0x04); |
3865 | aptpl = (buf[20] & 0x01); | 3863 | aptpl = (buf[20] & 0x01); |
3866 | } else { | 3864 | } else { |
3867 | aptpl = (buf[17] & 0x01); | 3865 | aptpl = (buf[17] & 0x01); |
3868 | unreg = (buf[17] & 0x02); | 3866 | unreg = (buf[17] & 0x02); |
3869 | } | 3867 | } |
3870 | transport_kunmap_data_sg(cmd); | 3868 | transport_kunmap_data_sg(cmd); |
3871 | buf = NULL; | 3869 | buf = NULL; |
3872 | 3870 | ||
3873 | /* | 3871 | /* |
3874 | * SPEC_I_PT=1 is only valid for Service action: REGISTER | 3872 | * SPEC_I_PT=1 is only valid for Service action: REGISTER |
3875 | */ | 3873 | */ |
3876 | if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { | 3874 | if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { |
3877 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3875 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3878 | ret = -EINVAL; | 3876 | ret = -EINVAL; |
3879 | goto out; | 3877 | goto out; |
3880 | } | 3878 | } |
3881 | 3879 | ||
3882 | /* | 3880 | /* |
3883 | * From spc4r17 section 6.14: | 3881 | * From spc4r17 section 6.14: |
3884 | * | 3882 | * |
3885 | * If the SPEC_I_PT bit is set to zero, the service action is not | 3883 | * If the SPEC_I_PT bit is set to zero, the service action is not |
3886 | * REGISTER AND MOVE, and the parameter list length is not 24, then | 3884 | * REGISTER AND MOVE, and the parameter list length is not 24, then |
3887 | * the command shall be terminated with CHECK CONDITION status, with | 3885 | * the command shall be terminated with CHECK CONDITION status, with |
3888 | * the sense key set to ILLEGAL REQUEST, and the additional sense | 3886 | * the sense key set to ILLEGAL REQUEST, and the additional sense |
3889 | * code set to PARAMETER LIST LENGTH ERROR. | 3887 | * code set to PARAMETER LIST LENGTH ERROR. |
3890 | */ | 3888 | */ |
3891 | if (!spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && | 3889 | if (!spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && |
3892 | (cmd->data_length != 24)) { | 3890 | (cmd->data_length != 24)) { |
3893 | pr_warn("SPC-PR: Received PR OUT illegal parameter" | 3891 | pr_warn("SPC-PR: Received PR OUT illegal parameter" |
3894 | " list length: %u\n", cmd->data_length); | 3892 | " list length: %u\n", cmd->data_length); |
3895 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; | 3893 | cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; |
3896 | ret = -EINVAL; | 3894 | ret = -EINVAL; |
3897 | goto out; | 3895 | goto out; |
3898 | } | 3896 | } |
3899 | /* | 3897 | /* |
3900 | * (core_scsi3_emulate_pro_* function parameters | 3898 | * (core_scsi3_emulate_pro_* function parameters |
3901 | * are defined by spc4r17 Table 174: | 3899 | * are defined by spc4r17 Table 174: |
3902 | * PERSISTENT_RESERVE_OUT service actions and valid parameters. | 3900 | * PERSISTENT_RESERVE_OUT service actions and valid parameters. |
3903 | */ | 3901 | */ |
3904 | switch (sa) { | 3902 | switch (sa) { |
3905 | case PRO_REGISTER: | 3903 | case PRO_REGISTER: |
3906 | ret = core_scsi3_emulate_pro_register(cmd, | 3904 | ret = core_scsi3_emulate_pro_register(cmd, |
3907 | res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); | 3905 | res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); |
3908 | break; | 3906 | break; |
3909 | case PRO_RESERVE: | 3907 | case PRO_RESERVE: |
3910 | ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key); | 3908 | ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key); |
3911 | break; | 3909 | break; |
3912 | case PRO_RELEASE: | 3910 | case PRO_RELEASE: |
3913 | ret = core_scsi3_emulate_pro_release(cmd, type, scope, res_key); | 3911 | ret = core_scsi3_emulate_pro_release(cmd, type, scope, res_key); |
3914 | break; | 3912 | break; |
3915 | case PRO_CLEAR: | 3913 | case PRO_CLEAR: |
3916 | ret = core_scsi3_emulate_pro_clear(cmd, res_key); | 3914 | ret = core_scsi3_emulate_pro_clear(cmd, res_key); |
3917 | break; | 3915 | break; |
3918 | case PRO_PREEMPT: | 3916 | case PRO_PREEMPT: |
3919 | ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, | 3917 | ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, |
3920 | res_key, sa_res_key, 0); | 3918 | res_key, sa_res_key, 0); |
3921 | break; | 3919 | break; |
3922 | case PRO_PREEMPT_AND_ABORT: | 3920 | case PRO_PREEMPT_AND_ABORT: |
3923 | ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, | 3921 | ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, |
3924 | res_key, sa_res_key, 1); | 3922 | res_key, sa_res_key, 1); |
3925 | break; | 3923 | break; |
3926 | case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: | 3924 | case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: |
3927 | ret = core_scsi3_emulate_pro_register(cmd, | 3925 | ret = core_scsi3_emulate_pro_register(cmd, |
3928 | 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); | 3926 | 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); |
3929 | break; | 3927 | break; |
3930 | case PRO_REGISTER_AND_MOVE: | 3928 | case PRO_REGISTER_AND_MOVE: |
3931 | ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key, | 3929 | ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key, |
3932 | sa_res_key, aptpl, unreg); | 3930 | sa_res_key, aptpl, unreg); |
3933 | break; | 3931 | break; |
3934 | default: | 3932 | default: |
3935 | pr_err("Unknown PERSISTENT_RESERVE_OUT service" | 3933 | pr_err("Unknown PERSISTENT_RESERVE_OUT service" |
3936 | " action: 0x%02x\n", cdb[1] & 0x1f); | 3934 | " action: 0x%02x\n", cdb[1] & 0x1f); |
3937 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 3935 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
3938 | ret = -EINVAL; | 3936 | ret = -EINVAL; |
3939 | break; | 3937 | break; |
3940 | } | 3938 | } |
3941 | 3939 | ||
3942 | out: | 3940 | out: |
3943 | if (!ret) { | 3941 | if (!ret) { |
3944 | task->task_scsi_status = GOOD; | 3942 | task->task_scsi_status = GOOD; |
3945 | transport_complete_task(task, 1); | 3943 | transport_complete_task(task, 1); |
3946 | } | 3944 | } |
3947 | return ret; | 3945 | return ret; |
3948 | } | 3946 | } |
3949 | 3947 | ||
3950 | /* | 3948 | /* |
3951 | * PERSISTENT_RESERVE_IN Service Action READ_KEYS | 3949 | * PERSISTENT_RESERVE_IN Service Action READ_KEYS |
3952 | * | 3950 | * |
3953 | * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160 | 3951 | * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160 |
3954 | */ | 3952 | */ |
3955 | static int core_scsi3_pri_read_keys(struct se_cmd *cmd) | 3953 | static int core_scsi3_pri_read_keys(struct se_cmd *cmd) |
3956 | { | 3954 | { |
3957 | struct se_device *se_dev = cmd->se_dev; | 3955 | struct se_device *se_dev = cmd->se_dev; |
3958 | struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; | 3956 | struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; |
3959 | struct t10_pr_registration *pr_reg; | 3957 | struct t10_pr_registration *pr_reg; |
3960 | unsigned char *buf; | 3958 | unsigned char *buf; |
3961 | u32 add_len = 0, off = 8; | 3959 | u32 add_len = 0, off = 8; |
3962 | 3960 | ||
3963 | if (cmd->data_length < 8) { | 3961 | if (cmd->data_length < 8) { |
3964 | pr_err("PRIN SA READ_KEYS SCSI Data Length: %u" | 3962 | pr_err("PRIN SA READ_KEYS SCSI Data Length: %u" |
3965 | " too small\n", cmd->data_length); | 3963 | " too small\n", cmd->data_length); |
3966 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 3964 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
3967 | return -EINVAL; | 3965 | return -EINVAL; |
3968 | } | 3966 | } |
3969 | 3967 | ||
3970 | buf = transport_kmap_data_sg(cmd); | 3968 | buf = transport_kmap_data_sg(cmd); |
3971 | buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); | 3969 | buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); |
3972 | buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); | 3970 | buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); |
3973 | buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); | 3971 | buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); |
3974 | buf[3] = (su_dev->t10_pr.pr_generation & 0xff); | 3972 | buf[3] = (su_dev->t10_pr.pr_generation & 0xff); |
3975 | 3973 | ||
3976 | spin_lock(&su_dev->t10_pr.registration_lock); | 3974 | spin_lock(&su_dev->t10_pr.registration_lock); |
3977 | list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, | 3975 | list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, |
3978 | pr_reg_list) { | 3976 | pr_reg_list) { |
3979 | /* | 3977 | /* |
3980 | * Check for overflow of 8byte PRI READ_KEYS payload and | 3978 | * Check for overflow of 8byte PRI READ_KEYS payload and |
3981 | * next reservation key list descriptor. | 3979 | * next reservation key list descriptor. |
3982 | */ | 3980 | */ |
3983 | if ((add_len + 8) > (cmd->data_length - 8)) | 3981 | if ((add_len + 8) > (cmd->data_length - 8)) |
3984 | break; | 3982 | break; |
3985 | 3983 | ||
3986 | buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); | 3984 | buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); |
3987 | buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); | 3985 | buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); |
3988 | buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); | 3986 | buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); |
3989 | buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); | 3987 | buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); |
3990 | buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); | 3988 | buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); |
3991 | buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); | 3989 | buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); |
3992 | buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); | 3990 | buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); |
3993 | buf[off++] = (pr_reg->pr_res_key & 0xff); | 3991 | buf[off++] = (pr_reg->pr_res_key & 0xff); |
3994 | 3992 | ||
3995 | add_len += 8; | 3993 | add_len += 8; |
3996 | } | 3994 | } |
3997 | spin_unlock(&su_dev->t10_pr.registration_lock); | 3995 | spin_unlock(&su_dev->t10_pr.registration_lock); |
3998 | 3996 | ||
3999 | buf[4] = ((add_len >> 24) & 0xff); | 3997 | buf[4] = ((add_len >> 24) & 0xff); |
4000 | buf[5] = ((add_len >> 16) & 0xff); | 3998 | buf[5] = ((add_len >> 16) & 0xff); |
4001 | buf[6] = ((add_len >> 8) & 0xff); | 3999 | buf[6] = ((add_len >> 8) & 0xff); |
4002 | buf[7] = (add_len & 0xff); | 4000 | buf[7] = (add_len & 0xff); |
4003 | 4001 | ||
4004 | transport_kunmap_data_sg(cmd); | 4002 | transport_kunmap_data_sg(cmd); |
4005 | 4003 | ||
4006 | return 0; | 4004 | return 0; |
4007 | } | 4005 | } |
4008 | 4006 | ||
4009 | /* | 4007 | /* |
4010 | * PERSISTENT_RESERVE_IN Service Action READ_RESERVATION | 4008 | * PERSISTENT_RESERVE_IN Service Action READ_RESERVATION |
4011 | * | 4009 | * |
4012 | * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162 | 4010 | * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162 |
4013 | */ | 4011 | */ |
4014 | static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) | 4012 | static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) |
4015 | { | 4013 | { |
4016 | struct se_device *se_dev = cmd->se_dev; | 4014 | struct se_device *se_dev = cmd->se_dev; |
4017 | struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; | 4015 | struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; |
4018 | struct t10_pr_registration *pr_reg; | 4016 | struct t10_pr_registration *pr_reg; |
4019 | unsigned char *buf; | 4017 | unsigned char *buf; |
4020 | u64 pr_res_key; | 4018 | u64 pr_res_key; |
4021 | u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */ | 4019 | u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */ |
4022 | 4020 | ||
4023 | if (cmd->data_length < 8) { | 4021 | if (cmd->data_length < 8) { |
4024 | pr_err("PRIN SA READ_RESERVATIONS SCSI Data Length: %u" | 4022 | pr_err("PRIN SA READ_RESERVATIONS SCSI Data Length: %u" |
4025 | " too small\n", cmd->data_length); | 4023 | " too small\n", cmd->data_length); |
4026 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 4024 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
4027 | return -EINVAL; | 4025 | return -EINVAL; |
4028 | } | 4026 | } |
4029 | 4027 | ||
4030 | buf = transport_kmap_data_sg(cmd); | 4028 | buf = transport_kmap_data_sg(cmd); |
4031 | buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); | 4029 | buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); |
4032 | buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); | 4030 | buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); |
4033 | buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); | 4031 | buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); |
4034 | buf[3] = (su_dev->t10_pr.pr_generation & 0xff); | 4032 | buf[3] = (su_dev->t10_pr.pr_generation & 0xff); |
4035 | 4033 | ||
4036 | spin_lock(&se_dev->dev_reservation_lock); | 4034 | spin_lock(&se_dev->dev_reservation_lock); |
4037 | pr_reg = se_dev->dev_pr_res_holder; | 4035 | pr_reg = se_dev->dev_pr_res_holder; |
4038 | if ((pr_reg)) { | 4036 | if ((pr_reg)) { |
4039 | /* | 4037 | /* |
4040 | * Set the hardcoded Additional Length | 4038 | * Set the hardcoded Additional Length |
4041 | */ | 4039 | */ |
4042 | buf[4] = ((add_len >> 24) & 0xff); | 4040 | buf[4] = ((add_len >> 24) & 0xff); |
4043 | buf[5] = ((add_len >> 16) & 0xff); | 4041 | buf[5] = ((add_len >> 16) & 0xff); |
4044 | buf[6] = ((add_len >> 8) & 0xff); | 4042 | buf[6] = ((add_len >> 8) & 0xff); |
4045 | buf[7] = (add_len & 0xff); | 4043 | buf[7] = (add_len & 0xff); |
4046 | 4044 | ||
4047 | if (cmd->data_length < 22) | 4045 | if (cmd->data_length < 22) |
4048 | goto err; | 4046 | goto err; |
4049 | 4047 | ||
4050 | /* | 4048 | /* |
4051 | * Set the Reservation key. | 4049 | * Set the Reservation key. |
4052 | * | 4050 | * |
4053 | * From spc4r17, section 5.7.10: | 4051 | * From spc4r17, section 5.7.10: |
4054 | * A persistent reservation holder has its reservation key | 4052 | * A persistent reservation holder has its reservation key |
4055 | * returned in the parameter data from a PERSISTENT | 4053 | * returned in the parameter data from a PERSISTENT |
4056 | * RESERVE IN command with READ RESERVATION service action as | 4054 | * RESERVE IN command with READ RESERVATION service action as |
4057 | * follows: | 4055 | * follows: |
4058 | * a) For a persistent reservation of the type Write Exclusive | 4056 | * a) For a persistent reservation of the type Write Exclusive |
4059 | * - All Registrants or Exclusive Access ยญ All Regitrants, | 4057 | * - All Registrants or Exclusive Access ยญ All Regitrants, |
4060 | * the reservation key shall be set to zero; or | 4058 | * the reservation key shall be set to zero; or |
4061 | * b) For all other persistent reservation types, the | 4059 | * b) For all other persistent reservation types, the |
4062 | * reservation key shall be set to the registered | 4060 | * reservation key shall be set to the registered |
4063 | * reservation key for the I_T nexus that holds the | 4061 | * reservation key for the I_T nexus that holds the |
4064 | * persistent reservation. | 4062 | * persistent reservation. |
4065 | */ | 4063 | */ |
4066 | if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | 4064 | if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || |
4067 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) | 4065 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) |
4068 | pr_res_key = 0; | 4066 | pr_res_key = 0; |
4069 | else | 4067 | else |
4070 | pr_res_key = pr_reg->pr_res_key; | 4068 | pr_res_key = pr_reg->pr_res_key; |
4071 | 4069 | ||
4072 | buf[8] = ((pr_res_key >> 56) & 0xff); | 4070 | buf[8] = ((pr_res_key >> 56) & 0xff); |
4073 | buf[9] = ((pr_res_key >> 48) & 0xff); | 4071 | buf[9] = ((pr_res_key >> 48) & 0xff); |
4074 | buf[10] = ((pr_res_key >> 40) & 0xff); | 4072 | buf[10] = ((pr_res_key >> 40) & 0xff); |
4075 | buf[11] = ((pr_res_key >> 32) & 0xff); | 4073 | buf[11] = ((pr_res_key >> 32) & 0xff); |
4076 | buf[12] = ((pr_res_key >> 24) & 0xff); | 4074 | buf[12] = ((pr_res_key >> 24) & 0xff); |
4077 | buf[13] = ((pr_res_key >> 16) & 0xff); | 4075 | buf[13] = ((pr_res_key >> 16) & 0xff); |
4078 | buf[14] = ((pr_res_key >> 8) & 0xff); | 4076 | buf[14] = ((pr_res_key >> 8) & 0xff); |
4079 | buf[15] = (pr_res_key & 0xff); | 4077 | buf[15] = (pr_res_key & 0xff); |
4080 | /* | 4078 | /* |
4081 | * Set the SCOPE and TYPE | 4079 | * Set the SCOPE and TYPE |
4082 | */ | 4080 | */ |
4083 | buf[21] = (pr_reg->pr_res_scope & 0xf0) | | 4081 | buf[21] = (pr_reg->pr_res_scope & 0xf0) | |
4084 | (pr_reg->pr_res_type & 0x0f); | 4082 | (pr_reg->pr_res_type & 0x0f); |
4085 | } | 4083 | } |
4086 | 4084 | ||
4087 | err: | 4085 | err: |
4088 | spin_unlock(&se_dev->dev_reservation_lock); | 4086 | spin_unlock(&se_dev->dev_reservation_lock); |
4089 | transport_kunmap_data_sg(cmd); | 4087 | transport_kunmap_data_sg(cmd); |
4090 | 4088 | ||
4091 | return 0; | 4089 | return 0; |
4092 | } | 4090 | } |
4093 | 4091 | ||
4094 | /* | 4092 | /* |
4095 | * PERSISTENT_RESERVE_IN Service Action REPORT_CAPABILITIES | 4093 | * PERSISTENT_RESERVE_IN Service Action REPORT_CAPABILITIES |
4096 | * | 4094 | * |
4097 | * See spc4r17 section 6.13.4 Table 165 | 4095 | * See spc4r17 section 6.13.4 Table 165 |
4098 | */ | 4096 | */ |
4099 | static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) | 4097 | static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) |
4100 | { | 4098 | { |
4101 | struct se_device *dev = cmd->se_dev; | 4099 | struct se_device *dev = cmd->se_dev; |
4102 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; | 4100 | struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; |
4103 | unsigned char *buf; | 4101 | unsigned char *buf; |
4104 | u16 add_len = 8; /* Hardcoded to 8. */ | 4102 | u16 add_len = 8; /* Hardcoded to 8. */ |
4105 | 4103 | ||
4106 | if (cmd->data_length < 6) { | 4104 | if (cmd->data_length < 6) { |
4107 | pr_err("PRIN SA REPORT_CAPABILITIES SCSI Data Length:" | 4105 | pr_err("PRIN SA REPORT_CAPABILITIES SCSI Data Length:" |
4108 | " %u too small\n", cmd->data_length); | 4106 | " %u too small\n", cmd->data_length); |
4109 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 4107 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
4110 | return -EINVAL; | 4108 | return -EINVAL; |
4111 | } | 4109 | } |
4112 | 4110 | ||
4113 | buf = transport_kmap_data_sg(cmd); | 4111 | buf = transport_kmap_data_sg(cmd); |
4114 | 4112 | ||
4115 | buf[0] = ((add_len << 8) & 0xff); | 4113 | buf[0] = ((add_len << 8) & 0xff); |
4116 | buf[1] = (add_len & 0xff); | 4114 | buf[1] = (add_len & 0xff); |
4117 | buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */ | 4115 | buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */ |
4118 | buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */ | 4116 | buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */ |
4119 | buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */ | 4117 | buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */ |
4120 | buf[2] |= 0x01; /* PTPL_C: Persistence across Target Power Loss bit */ | 4118 | buf[2] |= 0x01; /* PTPL_C: Persistence across Target Power Loss bit */ |
4121 | /* | 4119 | /* |
4122 | * We are filling in the PERSISTENT RESERVATION TYPE MASK below, so | 4120 | * We are filling in the PERSISTENT RESERVATION TYPE MASK below, so |
4123 | * set the TMV: Task Mask Valid bit. | 4121 | * set the TMV: Task Mask Valid bit. |
4124 | */ | 4122 | */ |
4125 | buf[3] |= 0x80; | 4123 | buf[3] |= 0x80; |
4126 | /* | 4124 | /* |
4127 | * Change ALLOW COMMANDs to 0x20 or 0x40 later from Table 166 | 4125 | * Change ALLOW COMMANDs to 0x20 or 0x40 later from Table 166 |
4128 | */ | 4126 | */ |
4129 | buf[3] |= 0x10; /* ALLOW COMMANDs field 001b */ | 4127 | buf[3] |= 0x10; /* ALLOW COMMANDs field 001b */ |
4130 | /* | 4128 | /* |
4131 | * PTPL_A: Persistence across Target Power Loss Active bit | 4129 | * PTPL_A: Persistence across Target Power Loss Active bit |
4132 | */ | 4130 | */ |
4133 | if (pr_tmpl->pr_aptpl_active) | 4131 | if (pr_tmpl->pr_aptpl_active) |
4134 | buf[3] |= 0x01; | 4132 | buf[3] |= 0x01; |
4135 | /* | 4133 | /* |
4136 | * Setup the PERSISTENT RESERVATION TYPE MASK from Table 167 | 4134 | * Setup the PERSISTENT RESERVATION TYPE MASK from Table 167 |
4137 | */ | 4135 | */ |
4138 | buf[4] |= 0x80; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ | 4136 | buf[4] |= 0x80; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ |
4139 | buf[4] |= 0x40; /* PR_TYPE_EXCLUSIVE_ACCESS_REGONLY */ | 4137 | buf[4] |= 0x40; /* PR_TYPE_EXCLUSIVE_ACCESS_REGONLY */ |
4140 | buf[4] |= 0x20; /* PR_TYPE_WRITE_EXCLUSIVE_REGONLY */ | 4138 | buf[4] |= 0x20; /* PR_TYPE_WRITE_EXCLUSIVE_REGONLY */ |
4141 | buf[4] |= 0x08; /* PR_TYPE_EXCLUSIVE_ACCESS */ | 4139 | buf[4] |= 0x08; /* PR_TYPE_EXCLUSIVE_ACCESS */ |
4142 | buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */ | 4140 | buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */ |
4143 | buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ | 4141 | buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ |
4144 | 4142 | ||
4145 | transport_kunmap_data_sg(cmd); | 4143 | transport_kunmap_data_sg(cmd); |
4146 | 4144 | ||
4147 | return 0; | 4145 | return 0; |
4148 | } | 4146 | } |
4149 | 4147 | ||
4150 | /* | 4148 | /* |
4151 | * PERSISTENT_RESERVE_IN Service Action READ_FULL_STATUS | 4149 | * PERSISTENT_RESERVE_IN Service Action READ_FULL_STATUS |
4152 | * | 4150 | * |
4153 | * See spc4r17 section 6.13.5 Table 168 and 169 | 4151 | * See spc4r17 section 6.13.5 Table 168 and 169 |
4154 | */ | 4152 | */ |
4155 | static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) | 4153 | static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) |
4156 | { | 4154 | { |
4157 | struct se_device *se_dev = cmd->se_dev; | 4155 | struct se_device *se_dev = cmd->se_dev; |
4158 | struct se_node_acl *se_nacl; | 4156 | struct se_node_acl *se_nacl; |
4159 | struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; | 4157 | struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; |
4160 | struct se_portal_group *se_tpg; | 4158 | struct se_portal_group *se_tpg; |
4161 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; | 4159 | struct t10_pr_registration *pr_reg, *pr_reg_tmp; |
4162 | struct t10_reservation *pr_tmpl = &se_dev->se_sub_dev->t10_pr; | 4160 | struct t10_reservation *pr_tmpl = &se_dev->se_sub_dev->t10_pr; |
4163 | unsigned char *buf; | 4161 | unsigned char *buf; |
4164 | u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; | 4162 | u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; |
4165 | u32 off = 8; /* off into first Full Status descriptor */ | 4163 | u32 off = 8; /* off into first Full Status descriptor */ |
4166 | int format_code = 0; | 4164 | int format_code = 0; |
4167 | 4165 | ||
4168 | if (cmd->data_length < 8) { | 4166 | if (cmd->data_length < 8) { |
4169 | pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u" | 4167 | pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u" |
4170 | " too small\n", cmd->data_length); | 4168 | " too small\n", cmd->data_length); |
4171 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 4169 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
4172 | return -EINVAL; | 4170 | return -EINVAL; |
4173 | } | 4171 | } |
4174 | 4172 | ||
4175 | buf = transport_kmap_data_sg(cmd); | 4173 | buf = transport_kmap_data_sg(cmd); |
4176 | 4174 | ||
4177 | buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); | 4175 | buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); |
4178 | buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); | 4176 | buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); |
4179 | buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); | 4177 | buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); |
4180 | buf[3] = (su_dev->t10_pr.pr_generation & 0xff); | 4178 | buf[3] = (su_dev->t10_pr.pr_generation & 0xff); |
4181 | 4179 | ||
4182 | spin_lock(&pr_tmpl->registration_lock); | 4180 | spin_lock(&pr_tmpl->registration_lock); |
4183 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 4181 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
4184 | &pr_tmpl->registration_list, pr_reg_list) { | 4182 | &pr_tmpl->registration_list, pr_reg_list) { |
4185 | 4183 | ||
4186 | se_nacl = pr_reg->pr_reg_nacl; | 4184 | se_nacl = pr_reg->pr_reg_nacl; |
4187 | se_tpg = pr_reg->pr_reg_nacl->se_tpg; | 4185 | se_tpg = pr_reg->pr_reg_nacl->se_tpg; |
4188 | add_desc_len = 0; | 4186 | add_desc_len = 0; |
4189 | 4187 | ||
4190 | atomic_inc(&pr_reg->pr_res_holders); | 4188 | atomic_inc(&pr_reg->pr_res_holders); |
4191 | smp_mb__after_atomic_inc(); | 4189 | smp_mb__after_atomic_inc(); |
4192 | spin_unlock(&pr_tmpl->registration_lock); | 4190 | spin_unlock(&pr_tmpl->registration_lock); |
4193 | /* | 4191 | /* |
4194 | * Determine expected length of $FABRIC_MOD specific | 4192 | * Determine expected length of $FABRIC_MOD specific |
4195 | * TransportID full status descriptor.. | 4193 | * TransportID full status descriptor.. |
4196 | */ | 4194 | */ |
4197 | exp_desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id_len( | 4195 | exp_desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id_len( |
4198 | se_tpg, se_nacl, pr_reg, &format_code); | 4196 | se_tpg, se_nacl, pr_reg, &format_code); |
4199 | 4197 | ||
4200 | if ((exp_desc_len + add_len) > cmd->data_length) { | 4198 | if ((exp_desc_len + add_len) > cmd->data_length) { |
4201 | pr_warn("SPC-3 PRIN READ_FULL_STATUS ran" | 4199 | pr_warn("SPC-3 PRIN READ_FULL_STATUS ran" |
4202 | " out of buffer: %d\n", cmd->data_length); | 4200 | " out of buffer: %d\n", cmd->data_length); |
4203 | spin_lock(&pr_tmpl->registration_lock); | 4201 | spin_lock(&pr_tmpl->registration_lock); |
4204 | atomic_dec(&pr_reg->pr_res_holders); | 4202 | atomic_dec(&pr_reg->pr_res_holders); |
4205 | smp_mb__after_atomic_dec(); | 4203 | smp_mb__after_atomic_dec(); |
4206 | break; | 4204 | break; |
4207 | } | 4205 | } |
4208 | /* | 4206 | /* |
4209 | * Set RESERVATION KEY | 4207 | * Set RESERVATION KEY |
4210 | */ | 4208 | */ |
4211 | buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); | 4209 | buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); |
4212 | buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); | 4210 | buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); |
4213 | buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); | 4211 | buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); |
4214 | buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); | 4212 | buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); |
4215 | buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); | 4213 | buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); |
4216 | buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); | 4214 | buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); |
4217 | buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); | 4215 | buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); |
4218 | buf[off++] = (pr_reg->pr_res_key & 0xff); | 4216 | buf[off++] = (pr_reg->pr_res_key & 0xff); |
4219 | off += 4; /* Skip Over Reserved area */ | 4217 | off += 4; /* Skip Over Reserved area */ |
4220 | 4218 | ||
4221 | /* | 4219 | /* |
4222 | * Set ALL_TG_PT bit if PROUT SA REGISTER had this set. | 4220 | * Set ALL_TG_PT bit if PROUT SA REGISTER had this set. |
4223 | */ | 4221 | */ |
4224 | if (pr_reg->pr_reg_all_tg_pt) | 4222 | if (pr_reg->pr_reg_all_tg_pt) |
4225 | buf[off] = 0x02; | 4223 | buf[off] = 0x02; |
4226 | /* | 4224 | /* |
4227 | * The struct se_lun pointer will be present for the | 4225 | * The struct se_lun pointer will be present for the |
4228 | * reservation holder for PR_HOLDER bit. | 4226 | * reservation holder for PR_HOLDER bit. |
4229 | * | 4227 | * |
4230 | * Also, if this registration is the reservation | 4228 | * Also, if this registration is the reservation |
4231 | * holder, fill in SCOPE and TYPE in the next byte. | 4229 | * holder, fill in SCOPE and TYPE in the next byte. |
4232 | */ | 4230 | */ |
4233 | if (pr_reg->pr_res_holder) { | 4231 | if (pr_reg->pr_res_holder) { |
4234 | buf[off++] |= 0x01; | 4232 | buf[off++] |= 0x01; |
4235 | buf[off++] = (pr_reg->pr_res_scope & 0xf0) | | 4233 | buf[off++] = (pr_reg->pr_res_scope & 0xf0) | |
4236 | (pr_reg->pr_res_type & 0x0f); | 4234 | (pr_reg->pr_res_type & 0x0f); |
4237 | } else | 4235 | } else |
4238 | off += 2; | 4236 | off += 2; |
4239 | 4237 | ||
4240 | off += 4; /* Skip over reserved area */ | 4238 | off += 4; /* Skip over reserved area */ |
4241 | /* | 4239 | /* |
4242 | * From spc4r17 6.3.15: | 4240 | * From spc4r17 6.3.15: |
4243 | * | 4241 | * |
4244 | * If the ALL_TG_PT bit set to zero, the RELATIVE TARGET PORT | 4242 | * If the ALL_TG_PT bit set to zero, the RELATIVE TARGET PORT |
4245 | * IDENTIFIER field contains the relative port identifier (see | 4243 | * IDENTIFIER field contains the relative port identifier (see |
4246 | * 3.1.120) of the target port that is part of the I_T nexus | 4244 | * 3.1.120) of the target port that is part of the I_T nexus |
4247 | * described by this full status descriptor. If the ALL_TG_PT | 4245 | * described by this full status descriptor. If the ALL_TG_PT |
4248 | * bit is set to one, the contents of the RELATIVE TARGET PORT | 4246 | * bit is set to one, the contents of the RELATIVE TARGET PORT |
4249 | * IDENTIFIER field are not defined by this standard. | 4247 | * IDENTIFIER field are not defined by this standard. |
4250 | */ | 4248 | */ |
4251 | if (!pr_reg->pr_reg_all_tg_pt) { | 4249 | if (!pr_reg->pr_reg_all_tg_pt) { |
4252 | struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep; | 4250 | struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep; |
4253 | 4251 | ||
4254 | buf[off++] = ((port->sep_rtpi >> 8) & 0xff); | 4252 | buf[off++] = ((port->sep_rtpi >> 8) & 0xff); |
4255 | buf[off++] = (port->sep_rtpi & 0xff); | 4253 | buf[off++] = (port->sep_rtpi & 0xff); |
4256 | } else | 4254 | } else |
4257 | off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */ | 4255 | off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */ |
4258 | 4256 | ||
4259 | /* | 4257 | /* |
4260 | * Now, have the $FABRIC_MOD fill in the protocol identifier | 4258 | * Now, have the $FABRIC_MOD fill in the protocol identifier |
4261 | */ | 4259 | */ |
4262 | desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id(se_tpg, | 4260 | desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id(se_tpg, |
4263 | se_nacl, pr_reg, &format_code, &buf[off+4]); | 4261 | se_nacl, pr_reg, &format_code, &buf[off+4]); |
4264 | 4262 | ||
4265 | spin_lock(&pr_tmpl->registration_lock); | 4263 | spin_lock(&pr_tmpl->registration_lock); |
4266 | atomic_dec(&pr_reg->pr_res_holders); | 4264 | atomic_dec(&pr_reg->pr_res_holders); |
4267 | smp_mb__after_atomic_dec(); | 4265 | smp_mb__after_atomic_dec(); |
4268 | /* | 4266 | /* |
4269 | * Set the ADDITIONAL DESCRIPTOR LENGTH | 4267 | * Set the ADDITIONAL DESCRIPTOR LENGTH |
4270 | */ | 4268 | */ |
4271 | buf[off++] = ((desc_len >> 24) & 0xff); | 4269 | buf[off++] = ((desc_len >> 24) & 0xff); |
4272 | buf[off++] = ((desc_len >> 16) & 0xff); | 4270 | buf[off++] = ((desc_len >> 16) & 0xff); |
4273 | buf[off++] = ((desc_len >> 8) & 0xff); | 4271 | buf[off++] = ((desc_len >> 8) & 0xff); |
4274 | buf[off++] = (desc_len & 0xff); | 4272 | buf[off++] = (desc_len & 0xff); |
4275 | /* | 4273 | /* |
4276 | * Size of full desctipor header minus TransportID | 4274 | * Size of full desctipor header minus TransportID |
4277 | * containing $FABRIC_MOD specific) initiator device/port | 4275 | * containing $FABRIC_MOD specific) initiator device/port |
4278 | * WWN information. | 4276 | * WWN information. |
4279 | * | 4277 | * |
4280 | * See spc4r17 Section 6.13.5 Table 169 | 4278 | * See spc4r17 Section 6.13.5 Table 169 |
4281 | */ | 4279 | */ |
4282 | add_desc_len = (24 + desc_len); | 4280 | add_desc_len = (24 + desc_len); |
4283 | 4281 | ||
4284 | off += desc_len; | 4282 | off += desc_len; |
4285 | add_len += add_desc_len; | 4283 | add_len += add_desc_len; |
4286 | } | 4284 | } |
4287 | spin_unlock(&pr_tmpl->registration_lock); | 4285 | spin_unlock(&pr_tmpl->registration_lock); |
4288 | /* | 4286 | /* |
4289 | * Set ADDITIONAL_LENGTH | 4287 | * Set ADDITIONAL_LENGTH |
4290 | */ | 4288 | */ |
4291 | buf[4] = ((add_len >> 24) & 0xff); | 4289 | buf[4] = ((add_len >> 24) & 0xff); |
4292 | buf[5] = ((add_len >> 16) & 0xff); | 4290 | buf[5] = ((add_len >> 16) & 0xff); |
4293 | buf[6] = ((add_len >> 8) & 0xff); | 4291 | buf[6] = ((add_len >> 8) & 0xff); |
4294 | buf[7] = (add_len & 0xff); | 4292 | buf[7] = (add_len & 0xff); |
4295 | 4293 | ||
4296 | transport_kunmap_data_sg(cmd); | 4294 | transport_kunmap_data_sg(cmd); |
4297 | 4295 | ||
4298 | return 0; | 4296 | return 0; |
4299 | } | 4297 | } |
4300 | 4298 | ||
4301 | int target_scsi3_emulate_pr_in(struct se_task *task) | 4299 | int target_scsi3_emulate_pr_in(struct se_task *task) |
4302 | { | 4300 | { |
4303 | struct se_cmd *cmd = task->task_se_cmd; | 4301 | struct se_cmd *cmd = task->task_se_cmd; |
4304 | int ret; | 4302 | int ret; |
4305 | 4303 | ||
4306 | /* | 4304 | /* |
4307 | * Following spc2r20 5.5.1 Reservations overview: | 4305 | * Following spc2r20 5.5.1 Reservations overview: |
4308 | * | 4306 | * |
4309 | * If a logical unit has been reserved by any RESERVE command and is | 4307 | * If a logical unit has been reserved by any RESERVE command and is |
4310 | * still reserved by any initiator, all PERSISTENT RESERVE IN and all | 4308 | * still reserved by any initiator, all PERSISTENT RESERVE IN and all |
4311 | * PERSISTENT RESERVE OUT commands shall conflict regardless of | 4309 | * PERSISTENT RESERVE OUT commands shall conflict regardless of |
4312 | * initiator or service action and shall terminate with a RESERVATION | 4310 | * initiator or service action and shall terminate with a RESERVATION |
4313 | * CONFLICT status. | 4311 | * CONFLICT status. |
4314 | */ | 4312 | */ |
4315 | if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { | 4313 | if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { |
4316 | pr_err("Received PERSISTENT_RESERVE CDB while legacy" | 4314 | pr_err("Received PERSISTENT_RESERVE CDB while legacy" |
4317 | " SPC-2 reservation is held, returning" | 4315 | " SPC-2 reservation is held, returning" |
4318 | " RESERVATION_CONFLICT\n"); | 4316 | " RESERVATION_CONFLICT\n"); |
4319 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; | 4317 | cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; |
4320 | return -EINVAL; | 4318 | return -EINVAL; |
4321 | } | 4319 | } |
4322 | 4320 | ||
4323 | switch (cmd->t_task_cdb[1] & 0x1f) { | 4321 | switch (cmd->t_task_cdb[1] & 0x1f) { |
4324 | case PRI_READ_KEYS: | 4322 | case PRI_READ_KEYS: |
4325 | ret = core_scsi3_pri_read_keys(cmd); | 4323 | ret = core_scsi3_pri_read_keys(cmd); |
4326 | break; | 4324 | break; |
4327 | case PRI_READ_RESERVATION: | 4325 | case PRI_READ_RESERVATION: |
4328 | ret = core_scsi3_pri_read_reservation(cmd); | 4326 | ret = core_scsi3_pri_read_reservation(cmd); |
4329 | break; | 4327 | break; |
4330 | case PRI_REPORT_CAPABILITIES: | 4328 | case PRI_REPORT_CAPABILITIES: |
4331 | ret = core_scsi3_pri_report_capabilities(cmd); | 4329 | ret = core_scsi3_pri_report_capabilities(cmd); |
4332 | break; | 4330 | break; |
4333 | case PRI_READ_FULL_STATUS: | 4331 | case PRI_READ_FULL_STATUS: |
4334 | ret = core_scsi3_pri_read_full_status(cmd); | 4332 | ret = core_scsi3_pri_read_full_status(cmd); |
4335 | break; | 4333 | break; |
4336 | default: | 4334 | default: |
4337 | pr_err("Unknown PERSISTENT_RESERVE_IN service" | 4335 | pr_err("Unknown PERSISTENT_RESERVE_IN service" |
4338 | " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); | 4336 | " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); |
4339 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; | 4337 | cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; |
4340 | ret = -EINVAL; | 4338 | ret = -EINVAL; |
4341 | break; | 4339 | break; |
4342 | } | 4340 | } |
4343 | 4341 | ||
4344 | if (!ret) { | 4342 | if (!ret) { |
4345 | task->task_scsi_status = GOOD; | 4343 | task->task_scsi_status = GOOD; |
4346 | transport_complete_task(task, 1); | 4344 | transport_complete_task(task, 1); |
4347 | } | 4345 | } |
4348 | return ret; | 4346 | return ret; |
4349 | } | 4347 | } |
4350 | 4348 | ||
4351 | static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) | 4349 | static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) |
4352 | { | 4350 | { |
4353 | return 0; | 4351 | return 0; |
4354 | } | 4352 | } |
4355 | 4353 | ||
4356 | static int core_pt_seq_non_holder( | 4354 | static int core_pt_seq_non_holder( |
4357 | struct se_cmd *cmd, | 4355 | struct se_cmd *cmd, |
4358 | unsigned char *cdb, | 4356 | unsigned char *cdb, |
4359 | u32 pr_reg_type) | 4357 | u32 pr_reg_type) |
4360 | { | 4358 | { |
4361 | return 0; | 4359 | return 0; |
4362 | } | 4360 | } |
4363 | 4361 | ||
4364 | int core_setup_reservations(struct se_device *dev, int force_pt) | 4362 | int core_setup_reservations(struct se_device *dev, int force_pt) |
4365 | { | 4363 | { |
4366 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; | 4364 | struct se_subsystem_dev *su_dev = dev->se_sub_dev; |
4367 | struct t10_reservation *rest = &su_dev->t10_pr; | 4365 | struct t10_reservation *rest = &su_dev->t10_pr; |
4368 | /* | 4366 | /* |
4369 | * If this device is from Target_Core_Mod/pSCSI, use the reservations | 4367 | * If this device is from Target_Core_Mod/pSCSI, use the reservations |
4370 | * of the Underlying SCSI hardware. In Linux/SCSI terms, this can | 4368 | * of the Underlying SCSI hardware. In Linux/SCSI terms, this can |
4371 | * cause a problem because libata and some SATA RAID HBAs appear | 4369 | * cause a problem because libata and some SATA RAID HBAs appear |
4372 | * under Linux/SCSI, but to emulate reservations themselves. | 4370 | * under Linux/SCSI, but to emulate reservations themselves. |
4373 | */ | 4371 | */ |
4374 | if (((dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && | 4372 | if (((dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && |
4375 | !(dev->se_sub_dev->se_dev_attrib.emulate_reservations)) || force_pt) { | 4373 | !(dev->se_sub_dev->se_dev_attrib.emulate_reservations)) || force_pt) { |
4376 | rest->res_type = SPC_PASSTHROUGH; | 4374 | rest->res_type = SPC_PASSTHROUGH; |
4377 | rest->pr_ops.t10_reservation_check = &core_pt_reservation_check; | 4375 | rest->pr_ops.t10_reservation_check = &core_pt_reservation_check; |
4378 | rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder; | 4376 | rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder; |
4379 | pr_debug("%s: Using SPC_PASSTHROUGH, no reservation" | 4377 | pr_debug("%s: Using SPC_PASSTHROUGH, no reservation" |
4380 | " emulation\n", dev->transport->name); | 4378 | " emulation\n", dev->transport->name); |
4381 | return 0; | 4379 | return 0; |
4382 | } | 4380 | } |
4383 | /* | 4381 | /* |
4384 | * If SPC-3 or above is reported by real or emulated struct se_device, | 4382 | * If SPC-3 or above is reported by real or emulated struct se_device, |
4385 | * use emulated Persistent Reservations. | 4383 | * use emulated Persistent Reservations. |
4386 | */ | 4384 | */ |
4387 | if (dev->transport->get_device_rev(dev) >= SCSI_3) { | 4385 | if (dev->transport->get_device_rev(dev) >= SCSI_3) { |
4388 | rest->res_type = SPC3_PERSISTENT_RESERVATIONS; | 4386 | rest->res_type = SPC3_PERSISTENT_RESERVATIONS; |
4389 | rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check; | 4387 | rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check; |
4390 | rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder; | 4388 | rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder; |
4391 | pr_debug("%s: Using SPC3_PERSISTENT_RESERVATIONS" | 4389 | pr_debug("%s: Using SPC3_PERSISTENT_RESERVATIONS" |
4392 | " emulation\n", dev->transport->name); | 4390 | " emulation\n", dev->transport->name); |
4393 | } else { | 4391 | } else { |
4394 | rest->res_type = SPC2_RESERVATIONS; | 4392 | rest->res_type = SPC2_RESERVATIONS; |
4395 | rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check; | 4393 | rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check; |
4396 | rest->pr_ops.t10_seq_non_holder = | 4394 | rest->pr_ops.t10_seq_non_holder = |
4397 | &core_scsi2_reservation_seq_non_holder; | 4395 | &core_scsi2_reservation_seq_non_holder; |
4398 | pr_debug("%s: Using SPC2_RESERVATIONS emulation\n", | 4396 | pr_debug("%s: Using SPC2_RESERVATIONS emulation\n", |
4399 | dev->transport->name); | 4397 | dev->transport->name); |
4400 | } | 4398 | } |
4401 | 4399 | ||
4402 | return 0; | 4400 | return 0; |
4403 | } | 4401 | } |
4404 | 4402 |