0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/slab.h>
0014 #include <linux/spinlock.h>
0015 #include <scsi/scsi_proto.h>
0016
0017 #include <target/target_core_base.h>
0018 #include <target/target_core_fabric.h>
0019
0020 #include "target_core_internal.h"
0021 #include "target_core_alua.h"
0022 #include "target_core_pr.h"
0023 #include "target_core_ua.h"
0024
0025 sense_reason_t
0026 target_scsi3_ua_check(struct se_cmd *cmd)
0027 {
0028 struct se_dev_entry *deve;
0029 struct se_session *sess = cmd->se_sess;
0030 struct se_node_acl *nacl;
0031
0032 if (!sess)
0033 return 0;
0034
0035 nacl = sess->se_node_acl;
0036 if (!nacl)
0037 return 0;
0038
0039 rcu_read_lock();
0040 deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
0041 if (!deve) {
0042 rcu_read_unlock();
0043 return 0;
0044 }
0045 if (list_empty_careful(&deve->ua_list)) {
0046 rcu_read_unlock();
0047 return 0;
0048 }
0049 rcu_read_unlock();
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 switch (cmd->t_task_cdb[0]) {
0066 case INQUIRY:
0067 case REPORT_LUNS:
0068 case REQUEST_SENSE:
0069 return 0;
0070 default:
0071 return TCM_CHECK_CONDITION_UNIT_ATTENTION;
0072 }
0073 }
0074
0075 int core_scsi3_ua_allocate(
0076 struct se_dev_entry *deve,
0077 u8 asc,
0078 u8 ascq)
0079 {
0080 struct se_ua *ua, *ua_p, *ua_tmp;
0081
0082 ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC);
0083 if (!ua) {
0084 pr_err("Unable to allocate struct se_ua\n");
0085 return -ENOMEM;
0086 }
0087 INIT_LIST_HEAD(&ua->ua_nacl_list);
0088
0089 ua->ua_asc = asc;
0090 ua->ua_ascq = ascq;
0091
0092 spin_lock(&deve->ua_lock);
0093 list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) {
0094
0095
0096
0097 if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) {
0098 spin_unlock(&deve->ua_lock);
0099 kmem_cache_free(se_ua_cache, ua);
0100 return 0;
0101 }
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 if (ua_p->ua_asc == 0x29) {
0122 if ((asc == 0x29) && (ascq > ua_p->ua_ascq))
0123 list_add(&ua->ua_nacl_list,
0124 &deve->ua_list);
0125 else
0126 list_add_tail(&ua->ua_nacl_list,
0127 &deve->ua_list);
0128 } else if (ua_p->ua_asc == 0x2a) {
0129
0130
0131
0132
0133 if ((asc == 0x29) || (ascq > ua_p->ua_asc))
0134 list_add(&ua->ua_nacl_list,
0135 &deve->ua_list);
0136 else
0137 list_add_tail(&ua->ua_nacl_list,
0138 &deve->ua_list);
0139 } else
0140 list_add_tail(&ua->ua_nacl_list,
0141 &deve->ua_list);
0142 spin_unlock(&deve->ua_lock);
0143
0144 return 0;
0145 }
0146 list_add_tail(&ua->ua_nacl_list, &deve->ua_list);
0147 spin_unlock(&deve->ua_lock);
0148
0149 pr_debug("Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:"
0150 " 0x%02x, ASCQ: 0x%02x\n", deve->mapped_lun,
0151 asc, ascq);
0152
0153 return 0;
0154 }
0155
0156 void target_ua_allocate_lun(struct se_node_acl *nacl,
0157 u32 unpacked_lun, u8 asc, u8 ascq)
0158 {
0159 struct se_dev_entry *deve;
0160
0161 if (!nacl)
0162 return;
0163
0164 rcu_read_lock();
0165 deve = target_nacl_find_deve(nacl, unpacked_lun);
0166 if (!deve) {
0167 rcu_read_unlock();
0168 return;
0169 }
0170
0171 core_scsi3_ua_allocate(deve, asc, ascq);
0172 rcu_read_unlock();
0173 }
0174
0175 void core_scsi3_ua_release_all(
0176 struct se_dev_entry *deve)
0177 {
0178 struct se_ua *ua, *ua_p;
0179
0180 spin_lock(&deve->ua_lock);
0181 list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
0182 list_del(&ua->ua_nacl_list);
0183 kmem_cache_free(se_ua_cache, ua);
0184 }
0185 spin_unlock(&deve->ua_lock);
0186 }
0187
0188
0189
0190
0191
0192
0193 bool core_scsi3_ua_for_check_condition(struct se_cmd *cmd, u8 *key, u8 *asc,
0194 u8 *ascq)
0195 {
0196 struct se_device *dev = cmd->se_dev;
0197 struct se_dev_entry *deve;
0198 struct se_session *sess = cmd->se_sess;
0199 struct se_node_acl *nacl;
0200 struct se_ua *ua = NULL, *ua_p;
0201 int head = 1;
0202 bool dev_ua_intlck_clear = (dev->dev_attrib.emulate_ua_intlck_ctrl
0203 == TARGET_UA_INTLCK_CTRL_CLEAR);
0204
0205 if (WARN_ON_ONCE(!sess))
0206 return false;
0207
0208 nacl = sess->se_node_acl;
0209 if (WARN_ON_ONCE(!nacl))
0210 return false;
0211
0212 rcu_read_lock();
0213 deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
0214 if (!deve) {
0215 rcu_read_unlock();
0216 *key = ILLEGAL_REQUEST;
0217 *asc = 0x25;
0218 *ascq = 0;
0219 return true;
0220 }
0221 *key = UNIT_ATTENTION;
0222
0223
0224
0225
0226
0227 spin_lock(&deve->ua_lock);
0228 list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
0229
0230
0231
0232
0233
0234 if (!dev_ua_intlck_clear) {
0235 *asc = ua->ua_asc;
0236 *ascq = ua->ua_ascq;
0237 break;
0238 }
0239
0240
0241
0242
0243
0244 if (head) {
0245 *asc = ua->ua_asc;
0246 *ascq = ua->ua_ascq;
0247 head = 0;
0248 }
0249 list_del(&ua->ua_nacl_list);
0250 kmem_cache_free(se_ua_cache, ua);
0251 }
0252 spin_unlock(&deve->ua_lock);
0253 rcu_read_unlock();
0254
0255 pr_debug("[%s]: %s UNIT ATTENTION condition with"
0256 " INTLCK_CTRL: %d, mapped LUN: %llu, got CDB: 0x%02x"
0257 " reported ASC: 0x%02x, ASCQ: 0x%02x\n",
0258 nacl->se_tpg->se_tpg_tfo->fabric_name,
0259 dev_ua_intlck_clear ? "Releasing" : "Reporting",
0260 dev->dev_attrib.emulate_ua_intlck_ctrl,
0261 cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq);
0262
0263 return head == 0;
0264 }
0265
0266 int core_scsi3_ua_clear_for_request_sense(
0267 struct se_cmd *cmd,
0268 u8 *asc,
0269 u8 *ascq)
0270 {
0271 struct se_dev_entry *deve;
0272 struct se_session *sess = cmd->se_sess;
0273 struct se_node_acl *nacl;
0274 struct se_ua *ua = NULL, *ua_p;
0275 int head = 1;
0276
0277 if (!sess)
0278 return -EINVAL;
0279
0280 nacl = sess->se_node_acl;
0281 if (!nacl)
0282 return -EINVAL;
0283
0284 rcu_read_lock();
0285 deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
0286 if (!deve) {
0287 rcu_read_unlock();
0288 return -EINVAL;
0289 }
0290 if (list_empty_careful(&deve->ua_list)) {
0291 rcu_read_unlock();
0292 return -EPERM;
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 spin_lock(&deve->ua_lock);
0305 list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
0306 if (head) {
0307 *asc = ua->ua_asc;
0308 *ascq = ua->ua_ascq;
0309 head = 0;
0310 }
0311 list_del(&ua->ua_nacl_list);
0312 kmem_cache_free(se_ua_cache, ua);
0313 }
0314 spin_unlock(&deve->ua_lock);
0315 rcu_read_unlock();
0316
0317 pr_debug("[%s]: Released UNIT ATTENTION condition, mapped"
0318 " LUN: %llu, got REQUEST_SENSE reported ASC: 0x%02x,"
0319 " ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->fabric_name,
0320 cmd->orig_fe_lun, *asc, *ascq);
0321
0322 return (head) ? -EPERM : 0;
0323 }