]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
c66ac9db NB |
2 | /******************************************************************************* |
3 | * Filename: target_core_ua.c | |
4 | * | |
5 | * This file contains logic for SPC-3 Unit Attention emulation | |
6 | * | |
4c76251e | 7 | * (c) Copyright 2009-2013 Datera, Inc. |
c66ac9db NB |
8 | * |
9 | * Nicholas A. Bellinger <[email protected]> | |
10 | * | |
c66ac9db NB |
11 | ******************************************************************************/ |
12 | ||
c66ac9db NB |
13 | #include <linux/slab.h> |
14 | #include <linux/spinlock.h> | |
ba929992 | 15 | #include <scsi/scsi_proto.h> |
c66ac9db NB |
16 | |
17 | #include <target/target_core_base.h> | |
c4795fb2 | 18 | #include <target/target_core_fabric.h> |
c66ac9db | 19 | |
e26d99ae | 20 | #include "target_core_internal.h" |
c66ac9db | 21 | #include "target_core_alua.h" |
c66ac9db NB |
22 | #include "target_core_pr.h" |
23 | #include "target_core_ua.h" | |
24 | ||
de103c93 CH |
25 | sense_reason_t |
26 | target_scsi3_ua_check(struct se_cmd *cmd) | |
c66ac9db NB |
27 | { |
28 | struct se_dev_entry *deve; | |
29 | struct se_session *sess = cmd->se_sess; | |
30 | struct se_node_acl *nacl; | |
31 | ||
6708bb27 | 32 | if (!sess) |
c66ac9db NB |
33 | return 0; |
34 | ||
35 | nacl = sess->se_node_acl; | |
6708bb27 | 36 | if (!nacl) |
c66ac9db NB |
37 | return 0; |
38 | ||
29a05dee NB |
39 | rcu_read_lock(); |
40 | deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); | |
41 | if (!deve) { | |
42 | rcu_read_unlock(); | |
c66ac9db | 43 | return 0; |
29a05dee | 44 | } |
e936a38a | 45 | if (list_empty_careful(&deve->ua_list)) { |
29a05dee NB |
46 | rcu_read_unlock(); |
47 | return 0; | |
48 | } | |
49 | rcu_read_unlock(); | |
c66ac9db NB |
50 | /* |
51 | * From sam4r14, section 5.14 Unit attention condition: | |
52 | * | |
53 | * a) if an INQUIRY command enters the enabled command state, the | |
54 | * device server shall process the INQUIRY command and shall neither | |
55 | * report nor clear any unit attention condition; | |
56 | * b) if a REPORT LUNS command enters the enabled command state, the | |
57 | * device server shall process the REPORT LUNS command and shall not | |
58 | * report any unit attention condition; | |
59 | * e) if a REQUEST SENSE command enters the enabled command state while | |
60 | * a unit attention condition exists for the SCSI initiator port | |
61 | * associated with the I_T nexus on which the REQUEST SENSE command | |
62 | * was received, then the device server shall process the command | |
63 | * and either: | |
64 | */ | |
de103c93 | 65 | switch (cmd->t_task_cdb[0]) { |
c66ac9db NB |
66 | case INQUIRY: |
67 | case REPORT_LUNS: | |
68 | case REQUEST_SENSE: | |
69 | return 0; | |
70 | default: | |
de103c93 | 71 | return TCM_CHECK_CONDITION_UNIT_ATTENTION; |
c66ac9db | 72 | } |
c66ac9db NB |
73 | } |
74 | ||
75 | int core_scsi3_ua_allocate( | |
c51c8e7b | 76 | struct se_dev_entry *deve, |
c66ac9db NB |
77 | u8 asc, |
78 | u8 ascq) | |
79 | { | |
c66ac9db | 80 | struct se_ua *ua, *ua_p, *ua_tmp; |
c66ac9db NB |
81 | |
82 | ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC); | |
6708bb27 AG |
83 | if (!ua) { |
84 | pr_err("Unable to allocate struct se_ua\n"); | |
e3d6f909 | 85 | return -ENOMEM; |
c66ac9db | 86 | } |
c66ac9db NB |
87 | INIT_LIST_HEAD(&ua->ua_nacl_list); |
88 | ||
c66ac9db NB |
89 | ua->ua_asc = asc; |
90 | ua->ua_ascq = ascq; | |
91 | ||
c66ac9db NB |
92 | spin_lock(&deve->ua_lock); |
93 | list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) { | |
94 | /* | |
95 | * Do not report the same UNIT ATTENTION twice.. | |
96 | */ | |
97 | if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) { | |
98 | spin_unlock(&deve->ua_lock); | |
c66ac9db NB |
99 | kmem_cache_free(se_ua_cache, ua); |
100 | return 0; | |
101 | } | |
102 | /* | |
103 | * Attach the highest priority Unit Attention to | |
104 | * the head of the list following sam4r14, | |
105 | * Section 5.14 Unit Attention Condition: | |
106 | * | |
107 | * POWER ON, RESET, OR BUS DEVICE RESET OCCURRED highest | |
108 | * POWER ON OCCURRED or | |
109 | * DEVICE INTERNAL RESET | |
110 | * SCSI BUS RESET OCCURRED or | |
111 | * MICROCODE HAS BEEN CHANGED or | |
112 | * protocol specific | |
113 | * BUS DEVICE RESET FUNCTION OCCURRED | |
114 | * I_T NEXUS LOSS OCCURRED | |
115 | * COMMANDS CLEARED BY POWER LOSS NOTIFICATION | |
116 | * all others Lowest | |
117 | * | |
118 | * Each of the ASCQ codes listed above are defined in | |
119 | * the 29h ASC family, see spc4r17 Table D.1 | |
120 | */ | |
121 | if (ua_p->ua_asc == 0x29) { | |
122 | if ((asc == 0x29) && (ascq > ua_p->ua_ascq)) | |
123 | list_add(&ua->ua_nacl_list, | |
124 | &deve->ua_list); | |
125 | else | |
126 | list_add_tail(&ua->ua_nacl_list, | |
127 | &deve->ua_list); | |
128 | } else if (ua_p->ua_asc == 0x2a) { | |
129 | /* | |
130 | * Incoming Family 29h ASCQ codes will override | |
131 | * Family 2AHh ASCQ codes for Unit Attention condition. | |
132 | */ | |
133 | if ((asc == 0x29) || (ascq > ua_p->ua_asc)) | |
134 | list_add(&ua->ua_nacl_list, | |
135 | &deve->ua_list); | |
136 | else | |
137 | list_add_tail(&ua->ua_nacl_list, | |
138 | &deve->ua_list); | |
139 | } else | |
140 | list_add_tail(&ua->ua_nacl_list, | |
141 | &deve->ua_list); | |
142 | spin_unlock(&deve->ua_lock); | |
c66ac9db | 143 | |
c66ac9db NB |
144 | return 0; |
145 | } | |
146 | list_add_tail(&ua->ua_nacl_list, &deve->ua_list); | |
147 | spin_unlock(&deve->ua_lock); | |
c66ac9db | 148 | |
c51c8e7b HR |
149 | pr_debug("Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:" |
150 | " 0x%02x, ASCQ: 0x%02x\n", deve->mapped_lun, | |
c66ac9db NB |
151 | asc, ascq); |
152 | ||
c66ac9db NB |
153 | return 0; |
154 | } | |
155 | ||
c51c8e7b HR |
156 | void target_ua_allocate_lun(struct se_node_acl *nacl, |
157 | u32 unpacked_lun, u8 asc, u8 ascq) | |
158 | { | |
159 | struct se_dev_entry *deve; | |
160 | ||
161 | if (!nacl) | |
162 | return; | |
163 | ||
164 | rcu_read_lock(); | |
165 | deve = target_nacl_find_deve(nacl, unpacked_lun); | |
166 | if (!deve) { | |
167 | rcu_read_unlock(); | |
168 | return; | |
169 | } | |
170 | ||
171 | core_scsi3_ua_allocate(deve, asc, ascq); | |
172 | rcu_read_unlock(); | |
173 | } | |
174 | ||
c66ac9db NB |
175 | void core_scsi3_ua_release_all( |
176 | struct se_dev_entry *deve) | |
177 | { | |
178 | struct se_ua *ua, *ua_p; | |
179 | ||
180 | spin_lock(&deve->ua_lock); | |
181 | list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { | |
182 | list_del(&ua->ua_nacl_list); | |
183 | kmem_cache_free(se_ua_cache, ua); | |
c66ac9db NB |
184 | } |
185 | spin_unlock(&deve->ua_lock); | |
186 | } | |
187 | ||
325c1e8b BVA |
188 | /* |
189 | * Dequeue a unit attention from the unit attention list. This function | |
190 | * returns true if the dequeuing succeeded and if *@key, *@asc and *@ascq have | |
191 | * been set. | |
192 | */ | |
193 | bool core_scsi3_ua_for_check_condition(struct se_cmd *cmd, u8 *key, u8 *asc, | |
194 | u8 *ascq) | |
c66ac9db | 195 | { |
5951146d | 196 | struct se_device *dev = cmd->se_dev; |
c66ac9db NB |
197 | struct se_dev_entry *deve; |
198 | struct se_session *sess = cmd->se_sess; | |
199 | struct se_node_acl *nacl; | |
200 | struct se_ua *ua = NULL, *ua_p; | |
201 | int head = 1; | |
1bf630fd DD |
202 | bool dev_ua_intlck_clear = (dev->dev_attrib.emulate_ua_intlck_ctrl |
203 | == TARGET_UA_INTLCK_CTRL_CLEAR); | |
c66ac9db | 204 | |
325c1e8b BVA |
205 | if (WARN_ON_ONCE(!sess)) |
206 | return false; | |
c66ac9db NB |
207 | |
208 | nacl = sess->se_node_acl; | |
325c1e8b BVA |
209 | if (WARN_ON_ONCE(!nacl)) |
210 | return false; | |
c66ac9db | 211 | |
29a05dee NB |
212 | rcu_read_lock(); |
213 | deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); | |
214 | if (!deve) { | |
215 | rcu_read_unlock(); | |
325c1e8b BVA |
216 | *key = ILLEGAL_REQUEST; |
217 | *asc = 0x25; /* LOGICAL UNIT NOT SUPPORTED */ | |
218 | *ascq = 0; | |
219 | return true; | |
c66ac9db | 220 | } |
325c1e8b | 221 | *key = UNIT_ATTENTION; |
c66ac9db NB |
222 | /* |
223 | * The highest priority Unit Attentions are placed at the head of the | |
224 | * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION + | |
225 | * sense data for the received CDB. | |
226 | */ | |
227 | spin_lock(&deve->ua_lock); | |
228 | list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { | |
229 | /* | |
230 | * For ua_intlck_ctrl code not equal to 00b, only report the | |
231 | * highest priority UNIT_ATTENTION and ASC/ASCQ without | |
232 | * clearing it. | |
233 | */ | |
1bf630fd | 234 | if (!dev_ua_intlck_clear) { |
c66ac9db NB |
235 | *asc = ua->ua_asc; |
236 | *ascq = ua->ua_ascq; | |
237 | break; | |
238 | } | |
239 | /* | |
240 | * Otherwise for the default 00b, release the UNIT ATTENTION | |
25985edc | 241 | * condition. Return the ASC/ASCQ of the highest priority UA |
c66ac9db NB |
242 | * (head of the list) in the outgoing CHECK_CONDITION + sense. |
243 | */ | |
244 | if (head) { | |
245 | *asc = ua->ua_asc; | |
246 | *ascq = ua->ua_ascq; | |
247 | head = 0; | |
248 | } | |
249 | list_del(&ua->ua_nacl_list); | |
250 | kmem_cache_free(se_ua_cache, ua); | |
c66ac9db NB |
251 | } |
252 | spin_unlock(&deve->ua_lock); | |
29a05dee | 253 | rcu_read_unlock(); |
c66ac9db | 254 | |
6708bb27 | 255 | pr_debug("[%s]: %s UNIT ATTENTION condition with" |
f2d30680 | 256 | " INTLCK_CTRL: %d, mapped LUN: %llu, got CDB: 0x%02x" |
c66ac9db | 257 | " reported ASC: 0x%02x, ASCQ: 0x%02x\n", |
30c7ca93 | 258 | nacl->se_tpg->se_tpg_tfo->fabric_name, |
1bf630fd DD |
259 | dev_ua_intlck_clear ? "Releasing" : "Reporting", |
260 | dev->dev_attrib.emulate_ua_intlck_ctrl, | |
a1d8b49a | 261 | cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq); |
325c1e8b BVA |
262 | |
263 | return head == 0; | |
c66ac9db NB |
264 | } |
265 | ||
266 | int core_scsi3_ua_clear_for_request_sense( | |
267 | struct se_cmd *cmd, | |
268 | u8 *asc, | |
269 | u8 *ascq) | |
270 | { | |
271 | struct se_dev_entry *deve; | |
272 | struct se_session *sess = cmd->se_sess; | |
273 | struct se_node_acl *nacl; | |
274 | struct se_ua *ua = NULL, *ua_p; | |
275 | int head = 1; | |
276 | ||
6708bb27 | 277 | if (!sess) |
e3d6f909 | 278 | return -EINVAL; |
c66ac9db NB |
279 | |
280 | nacl = sess->se_node_acl; | |
6708bb27 | 281 | if (!nacl) |
e3d6f909 | 282 | return -EINVAL; |
c66ac9db | 283 | |
29a05dee NB |
284 | rcu_read_lock(); |
285 | deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); | |
286 | if (!deve) { | |
287 | rcu_read_unlock(); | |
288 | return -EINVAL; | |
289 | } | |
e936a38a | 290 | if (list_empty_careful(&deve->ua_list)) { |
29a05dee | 291 | rcu_read_unlock(); |
e3d6f909 | 292 | return -EPERM; |
c66ac9db NB |
293 | } |
294 | /* | |
295 | * The highest priority Unit Attentions are placed at the head of the | |
296 | * struct se_dev_entry->ua_list. The First (and hence highest priority) | |
297 | * ASC/ASCQ will be returned in REQUEST_SENSE payload data for the | |
298 | * matching struct se_lun. | |
299 | * | |
300 | * Once the returning ASC/ASCQ values are set, we go ahead and | |
25985edc | 301 | * release all of the Unit Attention conditions for the associated |
c66ac9db NB |
302 | * struct se_lun. |
303 | */ | |
304 | spin_lock(&deve->ua_lock); | |
305 | list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { | |
306 | if (head) { | |
307 | *asc = ua->ua_asc; | |
308 | *ascq = ua->ua_ascq; | |
309 | head = 0; | |
310 | } | |
311 | list_del(&ua->ua_nacl_list); | |
312 | kmem_cache_free(se_ua_cache, ua); | |
c66ac9db NB |
313 | } |
314 | spin_unlock(&deve->ua_lock); | |
29a05dee | 315 | rcu_read_unlock(); |
c66ac9db | 316 | |
6708bb27 | 317 | pr_debug("[%s]: Released UNIT ATTENTION condition, mapped" |
f2d30680 | 318 | " LUN: %llu, got REQUEST_SENSE reported ASC: 0x%02x," |
30c7ca93 | 319 | " ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->fabric_name, |
c66ac9db NB |
320 | cmd->orig_fe_lun, *asc, *ascq); |
321 | ||
e3d6f909 | 322 | return (head) ? -EPERM : 0; |
c66ac9db | 323 | } |