root/drivers/target/target_core_ua.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. target_scsi3_ua_check
  2. core_scsi3_ua_allocate
  3. target_ua_allocate_lun
  4. core_scsi3_ua_release_all
  5. core_scsi3_ua_for_check_condition
  6. core_scsi3_ua_clear_for_request_sense

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*******************************************************************************
   3  * Filename: target_core_ua.c
   4  *
   5  * This file contains logic for SPC-3 Unit Attention emulation
   6  *
   7  * (c) Copyright 2009-2013 Datera, Inc.
   8  *
   9  * Nicholas A. Bellinger <nab@kernel.org>
  10  *
  11  ******************************************************************************/
  12 
  13 #include <linux/slab.h>
  14 #include <linux/spinlock.h>
  15 #include <scsi/scsi_proto.h>
  16 
  17 #include <target/target_core_base.h>
  18 #include <target/target_core_fabric.h>
  19 
  20 #include "target_core_internal.h"
  21 #include "target_core_alua.h"
  22 #include "target_core_pr.h"
  23 #include "target_core_ua.h"
  24 
  25 sense_reason_t
  26 target_scsi3_ua_check(struct se_cmd *cmd)
  27 {
  28         struct se_dev_entry *deve;
  29         struct se_session *sess = cmd->se_sess;
  30         struct se_node_acl *nacl;
  31 
  32         if (!sess)
  33                 return 0;
  34 
  35         nacl = sess->se_node_acl;
  36         if (!nacl)
  37                 return 0;
  38 
  39         rcu_read_lock();
  40         deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
  41         if (!deve) {
  42                 rcu_read_unlock();
  43                 return 0;
  44         }
  45         if (list_empty_careful(&deve->ua_list)) {
  46                 rcu_read_unlock();
  47                 return 0;
  48         }
  49         rcu_read_unlock();
  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          */
  65         switch (cmd->t_task_cdb[0]) {
  66         case INQUIRY:
  67         case REPORT_LUNS:
  68         case REQUEST_SENSE:
  69                 return 0;
  70         default:
  71                 return TCM_CHECK_CONDITION_UNIT_ATTENTION;
  72         }
  73 }
  74 
  75 int core_scsi3_ua_allocate(
  76         struct se_dev_entry *deve,
  77         u8 asc,
  78         u8 ascq)
  79 {
  80         struct se_ua *ua, *ua_p, *ua_tmp;
  81 
  82         ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC);
  83         if (!ua) {
  84                 pr_err("Unable to allocate struct se_ua\n");
  85                 return -ENOMEM;
  86         }
  87         INIT_LIST_HEAD(&ua->ua_nacl_list);
  88 
  89         ua->ua_asc = asc;
  90         ua->ua_ascq = ascq;
  91 
  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);
  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);
 143 
 144                 return 0;
 145         }
 146         list_add_tail(&ua->ua_nacl_list, &deve->ua_list);
 147         spin_unlock(&deve->ua_lock);
 148 
 149         pr_debug("Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:"
 150                 " 0x%02x, ASCQ: 0x%02x\n", deve->mapped_lun,
 151                 asc, ascq);
 152 
 153         return 0;
 154 }
 155 
 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 
 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);
 184         }
 185         spin_unlock(&deve->ua_lock);
 186 }
 187 
 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)
 195 {
 196         struct se_device *dev = cmd->se_dev;
 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;
 202 
 203         if (WARN_ON_ONCE(!sess))
 204                 return false;
 205 
 206         nacl = sess->se_node_acl;
 207         if (WARN_ON_ONCE(!nacl))
 208                 return false;
 209 
 210         rcu_read_lock();
 211         deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
 212         if (!deve) {
 213                 rcu_read_unlock();
 214                 *key = ILLEGAL_REQUEST;
 215                 *asc = 0x25; /* LOGICAL UNIT NOT SUPPORTED */
 216                 *ascq = 0;
 217                 return true;
 218         }
 219         *key = UNIT_ATTENTION;
 220         /*
 221          * The highest priority Unit Attentions are placed at the head of the
 222          * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION +
 223          * sense data for the received CDB.
 224          */
 225         spin_lock(&deve->ua_lock);
 226         list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
 227                 /*
 228                  * For ua_intlck_ctrl code not equal to 00b, only report the
 229                  * highest priority UNIT_ATTENTION and ASC/ASCQ without
 230                  * clearing it.
 231                  */
 232                 if (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) {
 233                         *asc = ua->ua_asc;
 234                         *ascq = ua->ua_ascq;
 235                         break;
 236                 }
 237                 /*
 238                  * Otherwise for the default 00b, release the UNIT ATTENTION
 239                  * condition.  Return the ASC/ASCQ of the highest priority UA
 240                  * (head of the list) in the outgoing CHECK_CONDITION + sense.
 241                  */
 242                 if (head) {
 243                         *asc = ua->ua_asc;
 244                         *ascq = ua->ua_ascq;
 245                         head = 0;
 246                 }
 247                 list_del(&ua->ua_nacl_list);
 248                 kmem_cache_free(se_ua_cache, ua);
 249         }
 250         spin_unlock(&deve->ua_lock);
 251         rcu_read_unlock();
 252 
 253         pr_debug("[%s]: %s UNIT ATTENTION condition with"
 254                 " INTLCK_CTRL: %d, mapped LUN: %llu, got CDB: 0x%02x"
 255                 " reported ASC: 0x%02x, ASCQ: 0x%02x\n",
 256                 nacl->se_tpg->se_tpg_tfo->fabric_name,
 257                 (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" :
 258                 "Releasing", dev->dev_attrib.emulate_ua_intlck_ctrl,
 259                 cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq);
 260 
 261         return head == 0;
 262 }
 263 
 264 int core_scsi3_ua_clear_for_request_sense(
 265         struct se_cmd *cmd,
 266         u8 *asc,
 267         u8 *ascq)
 268 {
 269         struct se_dev_entry *deve;
 270         struct se_session *sess = cmd->se_sess;
 271         struct se_node_acl *nacl;
 272         struct se_ua *ua = NULL, *ua_p;
 273         int head = 1;
 274 
 275         if (!sess)
 276                 return -EINVAL;
 277 
 278         nacl = sess->se_node_acl;
 279         if (!nacl)
 280                 return -EINVAL;
 281 
 282         rcu_read_lock();
 283         deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
 284         if (!deve) {
 285                 rcu_read_unlock();
 286                 return -EINVAL;
 287         }
 288         if (list_empty_careful(&deve->ua_list)) {
 289                 rcu_read_unlock();
 290                 return -EPERM;
 291         }
 292         /*
 293          * The highest priority Unit Attentions are placed at the head of the
 294          * struct se_dev_entry->ua_list.  The First (and hence highest priority)
 295          * ASC/ASCQ will be returned in REQUEST_SENSE payload data for the
 296          * matching struct se_lun.
 297          *
 298          * Once the returning ASC/ASCQ values are set, we go ahead and
 299          * release all of the Unit Attention conditions for the associated
 300          * struct se_lun.
 301          */
 302         spin_lock(&deve->ua_lock);
 303         list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
 304                 if (head) {
 305                         *asc = ua->ua_asc;
 306                         *ascq = ua->ua_ascq;
 307                         head = 0;
 308                 }
 309                 list_del(&ua->ua_nacl_list);
 310                 kmem_cache_free(se_ua_cache, ua);
 311         }
 312         spin_unlock(&deve->ua_lock);
 313         rcu_read_unlock();
 314 
 315         pr_debug("[%s]: Released UNIT ATTENTION condition, mapped"
 316                 " LUN: %llu, got REQUEST_SENSE reported ASC: 0x%02x,"
 317                 " ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->fabric_name,
 318                 cmd->orig_fe_lun, *asc, *ascq);
 319 
 320         return (head) ? -EPERM : 0;
 321 }

/* [<][>][^][v][top][bottom][index][help] */