Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
target_core_ua.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Filename: target_core_ua.c
3  *
4  * This file contains logic for SPC-3 Unit Attention emulation
5  *
6  * Copyright (c) 2009,2010 Rising Tide Systems
7  * Copyright (c) 2009,2010 Linux-iSCSI.org
8  *
9  * Nicholas A. Bellinger <[email protected]>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  ******************************************************************************/
26 
27 #include <linux/slab.h>
28 #include <linux/spinlock.h>
29 #include <scsi/scsi.h>
30 #include <scsi/scsi_cmnd.h>
31 
35 
36 #include "target_core_internal.h"
37 #include "target_core_alua.h"
38 #include "target_core_pr.h"
39 #include "target_core_ua.h"
40 
42  struct se_cmd *cmd,
43  unsigned char *cdb)
44 {
45  struct se_dev_entry *deve;
46  struct se_session *sess = cmd->se_sess;
47  struct se_node_acl *nacl;
48 
49  if (!sess)
50  return 0;
51 
52  nacl = sess->se_node_acl;
53  if (!nacl)
54  return 0;
55 
56  deve = nacl->device_list[cmd->orig_fe_lun];
57  if (!atomic_read(&deve->ua_count))
58  return 0;
59  /*
60  * From sam4r14, section 5.14 Unit attention condition:
61  *
62  * a) if an INQUIRY command enters the enabled command state, the
63  * device server shall process the INQUIRY command and shall neither
64  * report nor clear any unit attention condition;
65  * b) if a REPORT LUNS command enters the enabled command state, the
66  * device server shall process the REPORT LUNS command and shall not
67  * report any unit attention condition;
68  * e) if a REQUEST SENSE command enters the enabled command state while
69  * a unit attention condition exists for the SCSI initiator port
70  * associated with the I_T nexus on which the REQUEST SENSE command
71  * was received, then the device server shall process the command
72  * and either:
73  */
74  switch (cdb[0]) {
75  case INQUIRY:
76  case REPORT_LUNS:
77  case REQUEST_SENSE:
78  return 0;
79  default:
80  return -EINVAL;
81  }
82 
83  return -EINVAL;
84 }
85 
87  struct se_node_acl *nacl,
88  u32 unpacked_lun,
89  u8 asc,
90  u8 ascq)
91 {
92  struct se_dev_entry *deve;
93  struct se_ua *ua, *ua_p, *ua_tmp;
94  /*
95  * PASSTHROUGH OPS
96  */
97  if (!nacl)
98  return -EINVAL;
99 
100  ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC);
101  if (!ua) {
102  pr_err("Unable to allocate struct se_ua\n");
103  return -ENOMEM;
104  }
105  INIT_LIST_HEAD(&ua->ua_dev_list);
106  INIT_LIST_HEAD(&ua->ua_nacl_list);
107 
108  ua->ua_nacl = nacl;
109  ua->ua_asc = asc;
110  ua->ua_ascq = ascq;
111 
112  spin_lock_irq(&nacl->device_list_lock);
113  deve = nacl->device_list[unpacked_lun];
114 
115  spin_lock(&deve->ua_lock);
116  list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) {
117  /*
118  * Do not report the same UNIT ATTENTION twice..
119  */
120  if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) {
121  spin_unlock(&deve->ua_lock);
122  spin_unlock_irq(&nacl->device_list_lock);
124  return 0;
125  }
126  /*
127  * Attach the highest priority Unit Attention to
128  * the head of the list following sam4r14,
129  * Section 5.14 Unit Attention Condition:
130  *
131  * POWER ON, RESET, OR BUS DEVICE RESET OCCURRED highest
132  * POWER ON OCCURRED or
133  * DEVICE INTERNAL RESET
134  * SCSI BUS RESET OCCURRED or
135  * MICROCODE HAS BEEN CHANGED or
136  * protocol specific
137  * BUS DEVICE RESET FUNCTION OCCURRED
138  * I_T NEXUS LOSS OCCURRED
139  * COMMANDS CLEARED BY POWER LOSS NOTIFICATION
140  * all others Lowest
141  *
142  * Each of the ASCQ codes listed above are defined in
143  * the 29h ASC family, see spc4r17 Table D.1
144  */
145  if (ua_p->ua_asc == 0x29) {
146  if ((asc == 0x29) && (ascq > ua_p->ua_ascq))
147  list_add(&ua->ua_nacl_list,
148  &deve->ua_list);
149  else
151  &deve->ua_list);
152  } else if (ua_p->ua_asc == 0x2a) {
153  /*
154  * Incoming Family 29h ASCQ codes will override
155  * Family 2AHh ASCQ codes for Unit Attention condition.
156  */
157  if ((asc == 0x29) || (ascq > ua_p->ua_asc))
158  list_add(&ua->ua_nacl_list,
159  &deve->ua_list);
160  else
162  &deve->ua_list);
163  } else
165  &deve->ua_list);
166  spin_unlock(&deve->ua_lock);
167  spin_unlock_irq(&nacl->device_list_lock);
168 
169  atomic_inc(&deve->ua_count);
171  return 0;
172  }
173  list_add_tail(&ua->ua_nacl_list, &deve->ua_list);
174  spin_unlock(&deve->ua_lock);
175  spin_unlock_irq(&nacl->device_list_lock);
176 
177  pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:"
178  " 0x%02x, ASCQ: 0x%02x\n",
179  nacl->se_tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun,
180  asc, ascq);
181 
182  atomic_inc(&deve->ua_count);
184  return 0;
185 }
186 
188  struct se_dev_entry *deve)
189 {
190  struct se_ua *ua, *ua_p;
191 
192  spin_lock(&deve->ua_lock);
193  list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
194  list_del(&ua->ua_nacl_list);
196 
197  atomic_dec(&deve->ua_count);
199  }
200  spin_unlock(&deve->ua_lock);
201 }
202 
204  struct se_cmd *cmd,
205  u8 *asc,
206  u8 *ascq)
207 {
208  struct se_device *dev = cmd->se_dev;
209  struct se_dev_entry *deve;
210  struct se_session *sess = cmd->se_sess;
211  struct se_node_acl *nacl;
212  struct se_ua *ua = NULL, *ua_p;
213  int head = 1;
214 
215  if (!sess)
216  return;
217 
218  nacl = sess->se_node_acl;
219  if (!nacl)
220  return;
221 
222  spin_lock_irq(&nacl->device_list_lock);
223  deve = nacl->device_list[cmd->orig_fe_lun];
224  if (!atomic_read(&deve->ua_count)) {
225  spin_unlock_irq(&nacl->device_list_lock);
226  return;
227  }
228  /*
229  * The highest priority Unit Attentions are placed at the head of the
230  * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION +
231  * sense data for the received CDB.
232  */
233  spin_lock(&deve->ua_lock);
234  list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
235  /*
236  * For ua_intlck_ctrl code not equal to 00b, only report the
237  * highest priority UNIT_ATTENTION and ASC/ASCQ without
238  * clearing it.
239  */
240  if (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl != 0) {
241  *asc = ua->ua_asc;
242  *ascq = ua->ua_ascq;
243  break;
244  }
245  /*
246  * Otherwise for the default 00b, release the UNIT ATTENTION
247  * condition. Return the ASC/ASCQ of the highest priority UA
248  * (head of the list) in the outgoing CHECK_CONDITION + sense.
249  */
250  if (head) {
251  *asc = ua->ua_asc;
252  *ascq = ua->ua_ascq;
253  head = 0;
254  }
255  list_del(&ua->ua_nacl_list);
257 
258  atomic_dec(&deve->ua_count);
260  }
261  spin_unlock(&deve->ua_lock);
262  spin_unlock_irq(&nacl->device_list_lock);
263 
264  pr_debug("[%s]: %s UNIT ATTENTION condition with"
265  " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x"
266  " reported ASC: 0x%02x, ASCQ: 0x%02x\n",
267  nacl->se_tpg->se_tpg_tfo->get_fabric_name(),
268  (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" :
269  "Releasing", dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl,
270  cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq);
271 }
272 
274  struct se_cmd *cmd,
275  u8 *asc,
276  u8 *ascq)
277 {
278  struct se_dev_entry *deve;
279  struct se_session *sess = cmd->se_sess;
280  struct se_node_acl *nacl;
281  struct se_ua *ua = NULL, *ua_p;
282  int head = 1;
283 
284  if (!sess)
285  return -EINVAL;
286 
287  nacl = sess->se_node_acl;
288  if (!nacl)
289  return -EINVAL;
290 
291  spin_lock_irq(&nacl->device_list_lock);
292  deve = nacl->device_list[cmd->orig_fe_lun];
293  if (!atomic_read(&deve->ua_count)) {
294  spin_unlock_irq(&nacl->device_list_lock);
295  return -EPERM;
296  }
297  /*
298  * The highest priority Unit Attentions are placed at the head of the
299  * struct se_dev_entry->ua_list. The First (and hence highest priority)
300  * ASC/ASCQ will be returned in REQUEST_SENSE payload data for the
301  * matching struct se_lun.
302  *
303  * Once the returning ASC/ASCQ values are set, we go ahead and
304  * release all of the Unit Attention conditions for the associated
305  * struct se_lun.
306  */
307  spin_lock(&deve->ua_lock);
308  list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
309  if (head) {
310  *asc = ua->ua_asc;
311  *ascq = ua->ua_ascq;
312  head = 0;
313  }
314  list_del(&ua->ua_nacl_list);
316 
317  atomic_dec(&deve->ua_count);
319  }
320  spin_unlock(&deve->ua_lock);
321  spin_unlock_irq(&nacl->device_list_lock);
322 
323  pr_debug("[%s]: Released UNIT ATTENTION condition, mapped"
324  " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x,"
325  " ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(),
326  cmd->orig_fe_lun, *asc, *ascq);
327 
328  return (head) ? -EPERM : 0;
329 }