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