11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2c66ac9dbSNicholas Bellinger /******************************************************************************* 3c66ac9dbSNicholas Bellinger * Filename: target_core_alua.c 4c66ac9dbSNicholas Bellinger * 5c66ac9dbSNicholas Bellinger * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA) 6c66ac9dbSNicholas Bellinger * 74c76251eSNicholas Bellinger * (c) Copyright 2009-2013 Datera, Inc. 8c66ac9dbSNicholas Bellinger * 9c66ac9dbSNicholas Bellinger * Nicholas A. Bellinger <nab@kernel.org> 10c66ac9dbSNicholas Bellinger * 11c66ac9dbSNicholas Bellinger ******************************************************************************/ 12c66ac9dbSNicholas Bellinger 13c66ac9dbSNicholas Bellinger #include <linux/slab.h> 14c66ac9dbSNicholas Bellinger #include <linux/spinlock.h> 15c66ac9dbSNicholas Bellinger #include <linux/configfs.h> 168dcf07beSBart Van Assche #include <linux/delay.h> 17c53181afSPaul Gortmaker #include <linux/export.h> 188dcf07beSBart Van Assche #include <linux/fcntl.h> 190e9b10a9SAl Viro #include <linux/file.h> 208dcf07beSBart Van Assche #include <linux/fs.h> 21ba929992SBart Van Assche #include <scsi/scsi_proto.h> 2233395fb8SRoland Dreier #include <asm/unaligned.h> 23c66ac9dbSNicholas Bellinger 24c66ac9dbSNicholas Bellinger #include <target/target_core_base.h> 25c4795fb2SChristoph Hellwig #include <target/target_core_backend.h> 26c4795fb2SChristoph Hellwig #include <target/target_core_fabric.h> 27c66ac9dbSNicholas Bellinger 28e26d99aeSChristoph Hellwig #include "target_core_internal.h" 29c66ac9dbSNicholas Bellinger #include "target_core_alua.h" 30c66ac9dbSNicholas Bellinger #include "target_core_ua.h" 31c66ac9dbSNicholas Bellinger 32bb91c1a0SHannes Reinecke static sense_reason_t core_alua_check_transition(int state, int valid, 331ca4d4faSMike Christie int *primary, int explicit); 34c66ac9dbSNicholas Bellinger static int core_alua_set_tg_pt_secondary_state( 35adf653f9SChristoph Hellwig struct se_lun *lun, int explicit, int offline); 36c66ac9dbSNicholas Bellinger 37bb91c1a0SHannes Reinecke static char *core_alua_dump_state(int state); 38bb91c1a0SHannes Reinecke 39adf653f9SChristoph Hellwig static void __target_attach_tg_pt_gp(struct se_lun *lun, 40adf653f9SChristoph Hellwig struct t10_alua_tg_pt_gp *tg_pt_gp); 41adf653f9SChristoph Hellwig 42e3d6f909SAndy Grover static u16 alua_lu_gps_counter; 43e3d6f909SAndy Grover static u32 alua_lu_gps_count; 44e3d6f909SAndy Grover 45e3d6f909SAndy Grover static DEFINE_SPINLOCK(lu_gps_lock); 46e3d6f909SAndy Grover static LIST_HEAD(lu_gps_list); 47e3d6f909SAndy Grover 48e3d6f909SAndy Grover struct t10_alua_lu_gp *default_lu_gp; 49e3d6f909SAndy Grover 50c66ac9dbSNicholas Bellinger /* 51c66094bfSHannes Reinecke * REPORT REFERRALS 52c66094bfSHannes Reinecke * 53c66094bfSHannes Reinecke * See sbc3r35 section 5.23 54c66094bfSHannes Reinecke */ 55c66094bfSHannes Reinecke sense_reason_t 56c66094bfSHannes Reinecke target_emulate_report_referrals(struct se_cmd *cmd) 57c66094bfSHannes Reinecke { 58c66094bfSHannes Reinecke struct se_device *dev = cmd->se_dev; 59c66094bfSHannes Reinecke struct t10_alua_lba_map *map; 60c66094bfSHannes Reinecke struct t10_alua_lba_map_member *map_mem; 61c66094bfSHannes Reinecke unsigned char *buf; 62c66094bfSHannes Reinecke u32 rd_len = 0, off; 63c66094bfSHannes Reinecke 64c66094bfSHannes Reinecke if (cmd->data_length < 4) { 65c66094bfSHannes Reinecke pr_warn("REPORT REFERRALS allocation length %u too" 66c66094bfSHannes Reinecke " small\n", cmd->data_length); 67c66094bfSHannes Reinecke return TCM_INVALID_CDB_FIELD; 68c66094bfSHannes Reinecke } 69c66094bfSHannes Reinecke 70c66094bfSHannes Reinecke buf = transport_kmap_data_sg(cmd); 71c66094bfSHannes Reinecke if (!buf) 72c66094bfSHannes Reinecke return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 73c66094bfSHannes Reinecke 74c66094bfSHannes Reinecke off = 4; 75c66094bfSHannes Reinecke spin_lock(&dev->t10_alua.lba_map_lock); 76c66094bfSHannes Reinecke if (list_empty(&dev->t10_alua.lba_map_list)) { 77c66094bfSHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 78c66094bfSHannes Reinecke transport_kunmap_data_sg(cmd); 79c66094bfSHannes Reinecke 80c66094bfSHannes Reinecke return TCM_UNSUPPORTED_SCSI_OPCODE; 81c66094bfSHannes Reinecke } 82c66094bfSHannes Reinecke 83c66094bfSHannes Reinecke list_for_each_entry(map, &dev->t10_alua.lba_map_list, 84c66094bfSHannes Reinecke lba_map_list) { 85c66094bfSHannes Reinecke int desc_num = off + 3; 86c66094bfSHannes Reinecke int pg_num; 87c66094bfSHannes Reinecke 88c66094bfSHannes Reinecke off += 4; 8938edd724SHannes Reinecke if (cmd->data_length > off) 90c66094bfSHannes Reinecke put_unaligned_be64(map->lba_map_first_lba, &buf[off]); 91c66094bfSHannes Reinecke off += 8; 9238edd724SHannes Reinecke if (cmd->data_length > off) 93c66094bfSHannes Reinecke put_unaligned_be64(map->lba_map_last_lba, &buf[off]); 94c66094bfSHannes Reinecke off += 8; 95c66094bfSHannes Reinecke rd_len += 20; 96c66094bfSHannes Reinecke pg_num = 0; 97c66094bfSHannes Reinecke list_for_each_entry(map_mem, &map->lba_map_mem_list, 98c66094bfSHannes Reinecke lba_map_mem_list) { 9938edd724SHannes Reinecke int alua_state = map_mem->lba_map_mem_alua_state; 10038edd724SHannes Reinecke int alua_pg_id = map_mem->lba_map_mem_alua_pg_id; 10138edd724SHannes Reinecke 10238edd724SHannes Reinecke if (cmd->data_length > off) 10338edd724SHannes Reinecke buf[off] = alua_state & 0x0f; 10438edd724SHannes Reinecke off += 2; 10538edd724SHannes Reinecke if (cmd->data_length > off) 10638edd724SHannes Reinecke buf[off] = (alua_pg_id >> 8) & 0xff; 107c66094bfSHannes Reinecke off++; 10838edd724SHannes Reinecke if (cmd->data_length > off) 10938edd724SHannes Reinecke buf[off] = (alua_pg_id & 0xff); 11038edd724SHannes Reinecke off++; 111c66094bfSHannes Reinecke rd_len += 4; 112c66094bfSHannes Reinecke pg_num++; 113c66094bfSHannes Reinecke } 11438edd724SHannes Reinecke if (cmd->data_length > desc_num) 115c66094bfSHannes Reinecke buf[desc_num] = pg_num; 116c66094bfSHannes Reinecke } 117c66094bfSHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 118c66094bfSHannes Reinecke 119c66094bfSHannes Reinecke /* 120c66094bfSHannes Reinecke * Set the RETURN DATA LENGTH set in the header of the DataIN Payload 121c66094bfSHannes Reinecke */ 122c66094bfSHannes Reinecke put_unaligned_be16(rd_len, &buf[2]); 123c66094bfSHannes Reinecke 124c66094bfSHannes Reinecke transport_kunmap_data_sg(cmd); 125c66094bfSHannes Reinecke 126*14b40c1eSHannes Reinecke target_complete_cmd(cmd, SAM_STAT_GOOD); 127c66094bfSHannes Reinecke return 0; 128c66094bfSHannes Reinecke } 129c66094bfSHannes Reinecke 130c66094bfSHannes Reinecke /* 131c66ac9dbSNicholas Bellinger * REPORT_TARGET_PORT_GROUPS 132c66ac9dbSNicholas Bellinger * 133c66ac9dbSNicholas Bellinger * See spc4r17 section 6.27 134c66ac9dbSNicholas Bellinger */ 135de103c93SChristoph Hellwig sense_reason_t 136de103c93SChristoph Hellwig target_emulate_report_target_port_groups(struct se_cmd *cmd) 137c66ac9dbSNicholas Bellinger { 1380fd97ccfSChristoph Hellwig struct se_device *dev = cmd->se_dev; 139c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 140adf653f9SChristoph Hellwig struct se_lun *lun; 14105d1c7c0SAndy Grover unsigned char *buf; 1425b9a4d72SNicholas Bellinger u32 rd_len = 0, off; 1435b9a4d72SNicholas Bellinger int ext_hdr = (cmd->t_task_cdb[1] & 0x20); 144de103c93SChristoph Hellwig 1456b20fa9aSNicholas Bellinger /* 1465b9a4d72SNicholas Bellinger * Skip over RESERVED area to first Target port group descriptor 1475b9a4d72SNicholas Bellinger * depending on the PARAMETER DATA FORMAT type.. 1486b20fa9aSNicholas Bellinger */ 1495b9a4d72SNicholas Bellinger if (ext_hdr != 0) 1505b9a4d72SNicholas Bellinger off = 8; 1515b9a4d72SNicholas Bellinger else 1525b9a4d72SNicholas Bellinger off = 4; 1535b9a4d72SNicholas Bellinger 1545b9a4d72SNicholas Bellinger if (cmd->data_length < off) { 1555b9a4d72SNicholas Bellinger pr_warn("REPORT TARGET PORT GROUPS allocation length %u too" 1565b9a4d72SNicholas Bellinger " small for %s header\n", cmd->data_length, 1575b9a4d72SNicholas Bellinger (ext_hdr) ? "extended" : "normal"); 158de103c93SChristoph Hellwig return TCM_INVALID_CDB_FIELD; 1596b20fa9aSNicholas Bellinger } 1604949314cSAndy Grover buf = transport_kmap_data_sg(cmd); 161de103c93SChristoph Hellwig if (!buf) 162de103c93SChristoph Hellwig return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 16305d1c7c0SAndy Grover 1640fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 1650fd97ccfSChristoph Hellwig list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, 166c66ac9dbSNicholas Bellinger tg_pt_gp_list) { 167c66ac9dbSNicholas Bellinger /* 1686b20fa9aSNicholas Bellinger * Check if the Target port group and Target port descriptor list 1696b20fa9aSNicholas Bellinger * based on tg_pt_gp_members count will fit into the response payload. 1706b20fa9aSNicholas Bellinger * Otherwise, bump rd_len to let the initiator know we have exceeded 1716b20fa9aSNicholas Bellinger * the allocation length and the response is truncated. 1726b20fa9aSNicholas Bellinger */ 1736b20fa9aSNicholas Bellinger if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) > 1746b20fa9aSNicholas Bellinger cmd->data_length) { 1756b20fa9aSNicholas Bellinger rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4); 1766b20fa9aSNicholas Bellinger continue; 1776b20fa9aSNicholas Bellinger } 1786b20fa9aSNicholas Bellinger /* 179c66ac9dbSNicholas Bellinger * PREF: Preferred target port bit, determine if this 180c66ac9dbSNicholas Bellinger * bit should be set for port group. 181c66ac9dbSNicholas Bellinger */ 182c66ac9dbSNicholas Bellinger if (tg_pt_gp->tg_pt_gp_pref) 183c66ac9dbSNicholas Bellinger buf[off] = 0x80; 184c66ac9dbSNicholas Bellinger /* 185c66ac9dbSNicholas Bellinger * Set the ASYMMETRIC ACCESS State 186c66ac9dbSNicholas Bellinger */ 187d19c4643SMike Christie buf[off++] |= tg_pt_gp->tg_pt_gp_alua_access_state & 0xff; 188c66ac9dbSNicholas Bellinger /* 189c66ac9dbSNicholas Bellinger * Set supported ASYMMETRIC ACCESS State bits 190c66ac9dbSNicholas Bellinger */ 191c0dc941eSHannes Reinecke buf[off++] |= tg_pt_gp->tg_pt_gp_alua_supported_states; 192c66ac9dbSNicholas Bellinger /* 193c66ac9dbSNicholas Bellinger * TARGET PORT GROUP 194c66ac9dbSNicholas Bellinger */ 195a85d667eSBart Van Assche put_unaligned_be16(tg_pt_gp->tg_pt_gp_id, &buf[off]); 196a85d667eSBart Van Assche off += 2; 197c66ac9dbSNicholas Bellinger 198c66ac9dbSNicholas Bellinger off++; /* Skip over Reserved */ 199c66ac9dbSNicholas Bellinger /* 200c66ac9dbSNicholas Bellinger * STATUS CODE 201c66ac9dbSNicholas Bellinger */ 202c66ac9dbSNicholas Bellinger buf[off++] = (tg_pt_gp->tg_pt_gp_alua_access_status & 0xff); 203c66ac9dbSNicholas Bellinger /* 204c66ac9dbSNicholas Bellinger * Vendor Specific field 205c66ac9dbSNicholas Bellinger */ 206c66ac9dbSNicholas Bellinger buf[off++] = 0x00; 207c66ac9dbSNicholas Bellinger /* 208c66ac9dbSNicholas Bellinger * TARGET PORT COUNT 209c66ac9dbSNicholas Bellinger */ 210c66ac9dbSNicholas Bellinger buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff); 211c66ac9dbSNicholas Bellinger rd_len += 8; 212c66ac9dbSNicholas Bellinger 213c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 214adf653f9SChristoph Hellwig list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, 215adf653f9SChristoph Hellwig lun_tg_pt_gp_link) { 216c66ac9dbSNicholas Bellinger /* 217c66ac9dbSNicholas Bellinger * Start Target Port descriptor format 218c66ac9dbSNicholas Bellinger * 219c66ac9dbSNicholas Bellinger * See spc4r17 section 6.2.7 Table 247 220c66ac9dbSNicholas Bellinger */ 221c66ac9dbSNicholas Bellinger off += 2; /* Skip over Obsolete */ 222c66ac9dbSNicholas Bellinger /* 223c66ac9dbSNicholas Bellinger * Set RELATIVE TARGET PORT IDENTIFIER 224c66ac9dbSNicholas Bellinger */ 225a85d667eSBart Van Assche put_unaligned_be16(lun->lun_rtpi, &buf[off]); 226a85d667eSBart Van Assche off += 2; 227c66ac9dbSNicholas Bellinger rd_len += 4; 228c66ac9dbSNicholas Bellinger } 229c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 230c66ac9dbSNicholas Bellinger } 2310fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 232c66ac9dbSNicholas Bellinger /* 233c66ac9dbSNicholas Bellinger * Set the RETURN DATA LENGTH set in the header of the DataIN Payload 234c66ac9dbSNicholas Bellinger */ 2355b9a4d72SNicholas Bellinger put_unaligned_be32(rd_len, &buf[0]); 236c66ac9dbSNicholas Bellinger 2375b9a4d72SNicholas Bellinger /* 2385b9a4d72SNicholas Bellinger * Fill in the Extended header parameter data format if requested 2395b9a4d72SNicholas Bellinger */ 2405b9a4d72SNicholas Bellinger if (ext_hdr != 0) { 2415b9a4d72SNicholas Bellinger buf[4] = 0x10; 2425b9a4d72SNicholas Bellinger /* 243125d0119SHannes Reinecke * Set the implicit transition time (in seconds) for the application 2445b9a4d72SNicholas Bellinger * client to use as a base for it's transition timeout value. 2455b9a4d72SNicholas Bellinger * 2465b9a4d72SNicholas Bellinger * Use the current tg_pt_gp_mem -> tg_pt_gp membership from the LUN 2475b9a4d72SNicholas Bellinger * this CDB was received upon to determine this value individually 2485b9a4d72SNicholas Bellinger * for ALUA target port group. 2495b9a4d72SNicholas Bellinger */ 250adf653f9SChristoph Hellwig spin_lock(&cmd->se_lun->lun_tg_pt_gp_lock); 251adf653f9SChristoph Hellwig tg_pt_gp = cmd->se_lun->lun_tg_pt_gp; 2525b9a4d72SNicholas Bellinger if (tg_pt_gp) 253125d0119SHannes Reinecke buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; 254adf653f9SChristoph Hellwig spin_unlock(&cmd->se_lun->lun_tg_pt_gp_lock); 2555b9a4d72SNicholas Bellinger } 2564949314cSAndy Grover transport_kunmap_data_sg(cmd); 25705d1c7c0SAndy Grover 258*14b40c1eSHannes Reinecke target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, rd_len + 4); 259c66ac9dbSNicholas Bellinger return 0; 260c66ac9dbSNicholas Bellinger } 261c66ac9dbSNicholas Bellinger 262c66ac9dbSNicholas Bellinger /* 263125d0119SHannes Reinecke * SET_TARGET_PORT_GROUPS for explicit ALUA operation. 264c66ac9dbSNicholas Bellinger * 265c66ac9dbSNicholas Bellinger * See spc4r17 section 6.35 266c66ac9dbSNicholas Bellinger */ 267de103c93SChristoph Hellwig sense_reason_t 268de103c93SChristoph Hellwig target_emulate_set_target_port_groups(struct se_cmd *cmd) 269c66ac9dbSNicholas Bellinger { 2705951146dSAndy Grover struct se_device *dev = cmd->se_dev; 271adf653f9SChristoph Hellwig struct se_lun *l_lun = cmd->se_lun; 272e3d6f909SAndy Grover struct se_node_acl *nacl = cmd->se_sess->se_node_acl; 273c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp; 27405d1c7c0SAndy Grover unsigned char *buf; 27505d1c7c0SAndy Grover unsigned char *ptr; 276a0d50f62SHannes Reinecke sense_reason_t rc = TCM_NO_SENSE; 277c66ac9dbSNicholas Bellinger u32 len = 4; /* Skip over RESERVED area in header */ 278bb91c1a0SHannes Reinecke int alua_access_state, primary = 0, valid_states; 279c66ac9dbSNicholas Bellinger u16 tg_pt_id, rtpi; 280c66ac9dbSNicholas Bellinger 2810d7f1299SPaolo Bonzini if (cmd->data_length < 4) { 2820d7f1299SPaolo Bonzini pr_warn("SET TARGET PORT GROUPS parameter list length %u too" 2830d7f1299SPaolo Bonzini " small\n", cmd->data_length); 284de103c93SChristoph Hellwig return TCM_INVALID_PARAMETER_LIST; 2850d7f1299SPaolo Bonzini } 2860d7f1299SPaolo Bonzini 2874949314cSAndy Grover buf = transport_kmap_data_sg(cmd); 288de103c93SChristoph Hellwig if (!buf) 289de103c93SChristoph Hellwig return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 29005d1c7c0SAndy Grover 291c66ac9dbSNicholas Bellinger /* 292125d0119SHannes Reinecke * Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed 293c66ac9dbSNicholas Bellinger * for the local tg_pt_gp. 294c66ac9dbSNicholas Bellinger */ 295adf653f9SChristoph Hellwig spin_lock(&l_lun->lun_tg_pt_gp_lock); 296adf653f9SChristoph Hellwig l_tg_pt_gp = l_lun->lun_tg_pt_gp; 2976708bb27SAndy Grover if (!l_tg_pt_gp) { 298adf653f9SChristoph Hellwig spin_unlock(&l_lun->lun_tg_pt_gp_lock); 299adf653f9SChristoph Hellwig pr_err("Unable to access l_lun->tg_pt_gp\n"); 300de103c93SChristoph Hellwig rc = TCM_UNSUPPORTED_SCSI_OPCODE; 30105d1c7c0SAndy Grover goto out; 302c66ac9dbSNicholas Bellinger } 303c66ac9dbSNicholas Bellinger 304125d0119SHannes Reinecke if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { 305adf653f9SChristoph Hellwig spin_unlock(&l_lun->lun_tg_pt_gp_lock); 3066708bb27SAndy Grover pr_debug("Unable to process SET_TARGET_PORT_GROUPS" 307125d0119SHannes Reinecke " while TPGS_EXPLICIT_ALUA is disabled\n"); 308de103c93SChristoph Hellwig rc = TCM_UNSUPPORTED_SCSI_OPCODE; 30905d1c7c0SAndy Grover goto out; 310c66ac9dbSNicholas Bellinger } 311bb91c1a0SHannes Reinecke valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; 312adf653f9SChristoph Hellwig spin_unlock(&l_lun->lun_tg_pt_gp_lock); 313c66ac9dbSNicholas Bellinger 31405d1c7c0SAndy Grover ptr = &buf[4]; /* Skip over RESERVED area in header */ 31505d1c7c0SAndy Grover 316c66ac9dbSNicholas Bellinger while (len < cmd->data_length) { 317de103c93SChristoph Hellwig bool found = false; 318c66ac9dbSNicholas Bellinger alua_access_state = (ptr[0] & 0x0f); 319c66ac9dbSNicholas Bellinger /* 320c66ac9dbSNicholas Bellinger * Check the received ALUA access state, and determine if 321c66ac9dbSNicholas Bellinger * the state is a primary or secondary target port asymmetric 322c66ac9dbSNicholas Bellinger * access state. 323c66ac9dbSNicholas Bellinger */ 3241ca4d4faSMike Christie rc = core_alua_check_transition(alua_access_state, valid_states, 3251ca4d4faSMike Christie &primary, 1); 326de103c93SChristoph Hellwig if (rc) { 327c66ac9dbSNicholas Bellinger /* 328c66ac9dbSNicholas Bellinger * If the SET TARGET PORT GROUPS attempts to establish 329c66ac9dbSNicholas Bellinger * an invalid combination of target port asymmetric 330c66ac9dbSNicholas Bellinger * access states or attempts to establish an 331c66ac9dbSNicholas Bellinger * unsupported target port asymmetric access state, 332c66ac9dbSNicholas Bellinger * then the command shall be terminated with CHECK 333c66ac9dbSNicholas Bellinger * CONDITION status, with the sense key set to ILLEGAL 334c66ac9dbSNicholas Bellinger * REQUEST, and the additional sense code set to INVALID 335c66ac9dbSNicholas Bellinger * FIELD IN PARAMETER LIST. 336c66ac9dbSNicholas Bellinger */ 33705d1c7c0SAndy Grover goto out; 338c66ac9dbSNicholas Bellinger } 339de103c93SChristoph Hellwig 340c66ac9dbSNicholas Bellinger /* 341c66ac9dbSNicholas Bellinger * If the ASYMMETRIC ACCESS STATE field (see table 267) 342c66ac9dbSNicholas Bellinger * specifies a primary target port asymmetric access state, 343c66ac9dbSNicholas Bellinger * then the TARGET PORT GROUP OR TARGET PORT field specifies 344c66ac9dbSNicholas Bellinger * a primary target port group for which the primary target 345c66ac9dbSNicholas Bellinger * port asymmetric access state shall be changed. If the 346c66ac9dbSNicholas Bellinger * ASYMMETRIC ACCESS STATE field specifies a secondary target 347c66ac9dbSNicholas Bellinger * port asymmetric access state, then the TARGET PORT GROUP OR 348c66ac9dbSNicholas Bellinger * TARGET PORT field specifies the relative target port 349c66ac9dbSNicholas Bellinger * identifier (see 3.1.120) of the target port for which the 350c66ac9dbSNicholas Bellinger * secondary target port asymmetric access state shall be 351c66ac9dbSNicholas Bellinger * changed. 352c66ac9dbSNicholas Bellinger */ 353c66ac9dbSNicholas Bellinger if (primary) { 35433395fb8SRoland Dreier tg_pt_id = get_unaligned_be16(ptr + 2); 355c66ac9dbSNicholas Bellinger /* 356c66ac9dbSNicholas Bellinger * Locate the matching target port group ID from 357c66ac9dbSNicholas Bellinger * the global tg_pt_gp list 358c66ac9dbSNicholas Bellinger */ 3590fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 360c66ac9dbSNicholas Bellinger list_for_each_entry(tg_pt_gp, 3610fd97ccfSChristoph Hellwig &dev->t10_alua.tg_pt_gps_list, 362c66ac9dbSNicholas Bellinger tg_pt_gp_list) { 3636708bb27SAndy Grover if (!tg_pt_gp->tg_pt_gp_valid_id) 364c66ac9dbSNicholas Bellinger continue; 365c66ac9dbSNicholas Bellinger 366c66ac9dbSNicholas Bellinger if (tg_pt_id != tg_pt_gp->tg_pt_gp_id) 367c66ac9dbSNicholas Bellinger continue; 368c66ac9dbSNicholas Bellinger 36933940d09SJoern Engel atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); 370de103c93SChristoph Hellwig 3710fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 372c66ac9dbSNicholas Bellinger 373de103c93SChristoph Hellwig if (!core_alua_do_port_transition(tg_pt_gp, 374adf653f9SChristoph Hellwig dev, l_lun, nacl, 375de103c93SChristoph Hellwig alua_access_state, 1)) 376de103c93SChristoph Hellwig found = true; 377c66ac9dbSNicholas Bellinger 3780fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 37933940d09SJoern Engel atomic_dec_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); 380c66ac9dbSNicholas Bellinger break; 381c66ac9dbSNicholas Bellinger } 3820fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 383c66ac9dbSNicholas Bellinger } else { 384adf653f9SChristoph Hellwig struct se_lun *lun; 385adf653f9SChristoph Hellwig 386c66ac9dbSNicholas Bellinger /* 387f1ae05d5SHannes Reinecke * Extract the RELATIVE TARGET PORT IDENTIFIER to identify 388c66ac9dbSNicholas Bellinger * the Target Port in question for the the incoming 389c66ac9dbSNicholas Bellinger * SET_TARGET_PORT_GROUPS op. 390c66ac9dbSNicholas Bellinger */ 39133395fb8SRoland Dreier rtpi = get_unaligned_be16(ptr + 2); 392c66ac9dbSNicholas Bellinger /* 39335d1efe8SMasanari Iida * Locate the matching relative target port identifier 394c66ac9dbSNicholas Bellinger * for the struct se_device storage object. 395c66ac9dbSNicholas Bellinger */ 396c66ac9dbSNicholas Bellinger spin_lock(&dev->se_port_lock); 397adf653f9SChristoph Hellwig list_for_each_entry(lun, &dev->dev_sep_list, 398adf653f9SChristoph Hellwig lun_dev_link) { 399adf653f9SChristoph Hellwig if (lun->lun_rtpi != rtpi) 400c66ac9dbSNicholas Bellinger continue; 401c66ac9dbSNicholas Bellinger 402adf653f9SChristoph Hellwig // XXX: racy unlock 403c66ac9dbSNicholas Bellinger spin_unlock(&dev->se_port_lock); 404c66ac9dbSNicholas Bellinger 405de103c93SChristoph Hellwig if (!core_alua_set_tg_pt_secondary_state( 406adf653f9SChristoph Hellwig lun, 1, 1)) 407de103c93SChristoph Hellwig found = true; 408c66ac9dbSNicholas Bellinger 409c66ac9dbSNicholas Bellinger spin_lock(&dev->se_port_lock); 410c66ac9dbSNicholas Bellinger break; 411c66ac9dbSNicholas Bellinger } 412c66ac9dbSNicholas Bellinger spin_unlock(&dev->se_port_lock); 41305d1c7c0SAndy Grover } 414de103c93SChristoph Hellwig 415de103c93SChristoph Hellwig if (!found) { 416de103c93SChristoph Hellwig rc = TCM_INVALID_PARAMETER_LIST; 417de103c93SChristoph Hellwig goto out; 418c66ac9dbSNicholas Bellinger } 419c66ac9dbSNicholas Bellinger 420c66ac9dbSNicholas Bellinger ptr += 4; 421c66ac9dbSNicholas Bellinger len += 4; 422c66ac9dbSNicholas Bellinger } 423c66ac9dbSNicholas Bellinger 42405d1c7c0SAndy Grover out: 4254949314cSAndy Grover transport_kunmap_data_sg(cmd); 42659e4f541SRoland Dreier if (!rc) 427*14b40c1eSHannes Reinecke target_complete_cmd(cmd, SAM_STAT_GOOD); 42859e4f541SRoland Dreier return rc; 429c66ac9dbSNicholas Bellinger } 430c66ac9dbSNicholas Bellinger 4311e3ab99dSPaul Bolle static inline void set_ascq(struct se_cmd *cmd, u8 alua_ascq) 4321e3ab99dSPaul Bolle { 4331e3ab99dSPaul Bolle /* 4341e3ab99dSPaul Bolle * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; 4351e3ab99dSPaul Bolle * The ALUA additional sense code qualifier (ASCQ) is determined 4361e3ab99dSPaul Bolle * by the ALUA primary or secondary access state.. 4371e3ab99dSPaul Bolle */ 4381e3ab99dSPaul Bolle pr_debug("[%s]: ALUA TG Port not available, " 4391e3ab99dSPaul Bolle "SenseKey: NOT_READY, ASC/ASCQ: " 4401e3ab99dSPaul Bolle "0x04/0x%02x\n", 44130c7ca93SDavid Disseldorp cmd->se_tfo->fabric_name, alua_ascq); 4421e3ab99dSPaul Bolle 4431e3ab99dSPaul Bolle cmd->scsi_asc = 0x04; 4441e3ab99dSPaul Bolle cmd->scsi_ascq = alua_ascq; 4451e3ab99dSPaul Bolle } 4461e3ab99dSPaul Bolle 4471e3ab99dSPaul Bolle static inline void core_alua_state_nonoptimized( 448c66ac9dbSNicholas Bellinger struct se_cmd *cmd, 449c66ac9dbSNicholas Bellinger unsigned char *cdb, 4501e3ab99dSPaul Bolle int nonop_delay_msecs) 451c66ac9dbSNicholas Bellinger { 452c66ac9dbSNicholas Bellinger /* 453c66ac9dbSNicholas Bellinger * Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked 454c66ac9dbSNicholas Bellinger * later to determine if processing of this cmd needs to be 455c66ac9dbSNicholas Bellinger * temporarily delayed for the Active/NonOptimized primary access state. 456c66ac9dbSNicholas Bellinger */ 457c66ac9dbSNicholas Bellinger cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED; 458c66ac9dbSNicholas Bellinger cmd->alua_nonop_delay = nonop_delay_msecs; 459c66ac9dbSNicholas Bellinger } 460c66ac9dbSNicholas Bellinger 461c66094bfSHannes Reinecke static inline int core_alua_state_lba_dependent( 462c66094bfSHannes Reinecke struct se_cmd *cmd, 4631e3ab99dSPaul Bolle struct t10_alua_tg_pt_gp *tg_pt_gp) 464c66094bfSHannes Reinecke { 465c66094bfSHannes Reinecke struct se_device *dev = cmd->se_dev; 466c66094bfSHannes Reinecke u64 segment_size, segment_mult, sectors, lba; 467c66094bfSHannes Reinecke 468c66094bfSHannes Reinecke /* Only need to check for cdb actually containing LBAs */ 469c66094bfSHannes Reinecke if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB)) 470c66094bfSHannes Reinecke return 0; 471c66094bfSHannes Reinecke 472c66094bfSHannes Reinecke spin_lock(&dev->t10_alua.lba_map_lock); 473c66094bfSHannes Reinecke segment_size = dev->t10_alua.lba_map_segment_size; 474c66094bfSHannes Reinecke segment_mult = dev->t10_alua.lba_map_segment_multiplier; 475c66094bfSHannes Reinecke sectors = cmd->data_length / dev->dev_attrib.block_size; 476c66094bfSHannes Reinecke 477c66094bfSHannes Reinecke lba = cmd->t_task_lba; 478c66094bfSHannes Reinecke while (lba < cmd->t_task_lba + sectors) { 479c66094bfSHannes Reinecke struct t10_alua_lba_map *cur_map = NULL, *map; 480c66094bfSHannes Reinecke struct t10_alua_lba_map_member *map_mem; 481c66094bfSHannes Reinecke 482c66094bfSHannes Reinecke list_for_each_entry(map, &dev->t10_alua.lba_map_list, 483c66094bfSHannes Reinecke lba_map_list) { 484c66094bfSHannes Reinecke u64 start_lba, last_lba; 485c66094bfSHannes Reinecke u64 first_lba = map->lba_map_first_lba; 486c66094bfSHannes Reinecke 487c66094bfSHannes Reinecke if (segment_mult) { 488c66094bfSHannes Reinecke u64 tmp = lba; 489cdf55949SNicholas Bellinger start_lba = do_div(tmp, segment_size * segment_mult); 490c66094bfSHannes Reinecke 491c66094bfSHannes Reinecke last_lba = first_lba + segment_size - 1; 492c66094bfSHannes Reinecke if (start_lba >= first_lba && 493c66094bfSHannes Reinecke start_lba <= last_lba) { 494c66094bfSHannes Reinecke lba += segment_size; 495c66094bfSHannes Reinecke cur_map = map; 496c66094bfSHannes Reinecke break; 497c66094bfSHannes Reinecke } 498c66094bfSHannes Reinecke } else { 499c66094bfSHannes Reinecke last_lba = map->lba_map_last_lba; 500c66094bfSHannes Reinecke if (lba >= first_lba && lba <= last_lba) { 501c66094bfSHannes Reinecke lba = last_lba + 1; 502c66094bfSHannes Reinecke cur_map = map; 503c66094bfSHannes Reinecke break; 504c66094bfSHannes Reinecke } 505c66094bfSHannes Reinecke } 506c66094bfSHannes Reinecke } 507c66094bfSHannes Reinecke if (!cur_map) { 508c66094bfSHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 5091e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); 510c66094bfSHannes Reinecke return 1; 511c66094bfSHannes Reinecke } 512c66094bfSHannes Reinecke list_for_each_entry(map_mem, &cur_map->lba_map_mem_list, 513c66094bfSHannes Reinecke lba_map_mem_list) { 514c66094bfSHannes Reinecke if (map_mem->lba_map_mem_alua_pg_id != 515c66094bfSHannes Reinecke tg_pt_gp->tg_pt_gp_id) 516c66094bfSHannes Reinecke continue; 517c66094bfSHannes Reinecke switch(map_mem->lba_map_mem_alua_state) { 518c66094bfSHannes Reinecke case ALUA_ACCESS_STATE_STANDBY: 519c66094bfSHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 5201e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); 521c66094bfSHannes Reinecke return 1; 522c66094bfSHannes Reinecke case ALUA_ACCESS_STATE_UNAVAILABLE: 523c66094bfSHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 5241e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); 525c66094bfSHannes Reinecke return 1; 526c66094bfSHannes Reinecke default: 527c66094bfSHannes Reinecke break; 528c66094bfSHannes Reinecke } 529c66094bfSHannes Reinecke } 530c66094bfSHannes Reinecke } 531c66094bfSHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 532c66094bfSHannes Reinecke return 0; 533c66094bfSHannes Reinecke } 534c66094bfSHannes Reinecke 535c66ac9dbSNicholas Bellinger static inline int core_alua_state_standby( 536c66ac9dbSNicholas Bellinger struct se_cmd *cmd, 5371e3ab99dSPaul Bolle unsigned char *cdb) 538c66ac9dbSNicholas Bellinger { 539c66ac9dbSNicholas Bellinger /* 540c66ac9dbSNicholas Bellinger * Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by 541c66ac9dbSNicholas Bellinger * spc4r17 section 5.9.2.4.4 542c66ac9dbSNicholas Bellinger */ 543c66ac9dbSNicholas Bellinger switch (cdb[0]) { 544c66ac9dbSNicholas Bellinger case INQUIRY: 545c66ac9dbSNicholas Bellinger case LOG_SELECT: 546c66ac9dbSNicholas Bellinger case LOG_SENSE: 547c66ac9dbSNicholas Bellinger case MODE_SELECT: 548c66ac9dbSNicholas Bellinger case MODE_SENSE: 549c66ac9dbSNicholas Bellinger case REPORT_LUNS: 550c66ac9dbSNicholas Bellinger case RECEIVE_DIAGNOSTIC: 551c66ac9dbSNicholas Bellinger case SEND_DIAGNOSTIC: 552e7810c2dSNicholas Bellinger case READ_CAPACITY: 55330f359a6SNicholas Bellinger return 0; 554eb846d9fSHannes Reinecke case SERVICE_ACTION_IN_16: 555e7810c2dSNicholas Bellinger switch (cdb[1] & 0x1f) { 556e7810c2dSNicholas Bellinger case SAI_READ_CAPACITY_16: 557e7810c2dSNicholas Bellinger return 0; 558e7810c2dSNicholas Bellinger default: 559e7810c2dSNicholas Bellinger set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); 560e7810c2dSNicholas Bellinger return 1; 561e7810c2dSNicholas Bellinger } 562c66ac9dbSNicholas Bellinger case MAINTENANCE_IN: 563ba539743SNicholas Bellinger switch (cdb[1] & 0x1f) { 564c66ac9dbSNicholas Bellinger case MI_REPORT_TARGET_PGS: 565c66ac9dbSNicholas Bellinger return 0; 566c66ac9dbSNicholas Bellinger default: 5671e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); 568c66ac9dbSNicholas Bellinger return 1; 569c66ac9dbSNicholas Bellinger } 570c66ac9dbSNicholas Bellinger case MAINTENANCE_OUT: 571c66ac9dbSNicholas Bellinger switch (cdb[1]) { 572c66ac9dbSNicholas Bellinger case MO_SET_TARGET_PGS: 573c66ac9dbSNicholas Bellinger return 0; 574c66ac9dbSNicholas Bellinger default: 5751e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); 576c66ac9dbSNicholas Bellinger return 1; 577c66ac9dbSNicholas Bellinger } 578c66ac9dbSNicholas Bellinger case REQUEST_SENSE: 579c66ac9dbSNicholas Bellinger case PERSISTENT_RESERVE_IN: 580c66ac9dbSNicholas Bellinger case PERSISTENT_RESERVE_OUT: 581c66ac9dbSNicholas Bellinger case READ_BUFFER: 582c66ac9dbSNicholas Bellinger case WRITE_BUFFER: 583c66ac9dbSNicholas Bellinger return 0; 584c66ac9dbSNicholas Bellinger default: 5851e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY); 586c66ac9dbSNicholas Bellinger return 1; 587c66ac9dbSNicholas Bellinger } 588c66ac9dbSNicholas Bellinger 589c66ac9dbSNicholas Bellinger return 0; 590c66ac9dbSNicholas Bellinger } 591c66ac9dbSNicholas Bellinger 592c66ac9dbSNicholas Bellinger static inline int core_alua_state_unavailable( 593c66ac9dbSNicholas Bellinger struct se_cmd *cmd, 5941e3ab99dSPaul Bolle unsigned char *cdb) 595c66ac9dbSNicholas Bellinger { 596c66ac9dbSNicholas Bellinger /* 597c66ac9dbSNicholas Bellinger * Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by 598c66ac9dbSNicholas Bellinger * spc4r17 section 5.9.2.4.5 599c66ac9dbSNicholas Bellinger */ 600c66ac9dbSNicholas Bellinger switch (cdb[0]) { 601c66ac9dbSNicholas Bellinger case INQUIRY: 602c66ac9dbSNicholas Bellinger case REPORT_LUNS: 60330f359a6SNicholas Bellinger return 0; 604c66ac9dbSNicholas Bellinger case MAINTENANCE_IN: 605ba539743SNicholas Bellinger switch (cdb[1] & 0x1f) { 606c66ac9dbSNicholas Bellinger case MI_REPORT_TARGET_PGS: 607c66ac9dbSNicholas Bellinger return 0; 608c66ac9dbSNicholas Bellinger default: 6091e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); 610c66ac9dbSNicholas Bellinger return 1; 611c66ac9dbSNicholas Bellinger } 612c66ac9dbSNicholas Bellinger case MAINTENANCE_OUT: 613c66ac9dbSNicholas Bellinger switch (cdb[1]) { 614c66ac9dbSNicholas Bellinger case MO_SET_TARGET_PGS: 615c66ac9dbSNicholas Bellinger return 0; 616c66ac9dbSNicholas Bellinger default: 6171e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); 618c66ac9dbSNicholas Bellinger return 1; 619c66ac9dbSNicholas Bellinger } 620c66ac9dbSNicholas Bellinger case REQUEST_SENSE: 621c66ac9dbSNicholas Bellinger case READ_BUFFER: 622c66ac9dbSNicholas Bellinger case WRITE_BUFFER: 623c66ac9dbSNicholas Bellinger return 0; 624c66ac9dbSNicholas Bellinger default: 6251e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE); 626c66ac9dbSNicholas Bellinger return 1; 627c66ac9dbSNicholas Bellinger } 628c66ac9dbSNicholas Bellinger 629c66ac9dbSNicholas Bellinger return 0; 630c66ac9dbSNicholas Bellinger } 631c66ac9dbSNicholas Bellinger 632c66ac9dbSNicholas Bellinger static inline int core_alua_state_transition( 633c66ac9dbSNicholas Bellinger struct se_cmd *cmd, 6341e3ab99dSPaul Bolle unsigned char *cdb) 635c66ac9dbSNicholas Bellinger { 636c66ac9dbSNicholas Bellinger /* 637f1ae05d5SHannes Reinecke * Allowed CDBs for ALUA_ACCESS_STATE_TRANSITION as defined by 638c66ac9dbSNicholas Bellinger * spc4r17 section 5.9.2.5 639c66ac9dbSNicholas Bellinger */ 640c66ac9dbSNicholas Bellinger switch (cdb[0]) { 641c66ac9dbSNicholas Bellinger case INQUIRY: 642c66ac9dbSNicholas Bellinger case REPORT_LUNS: 64330f359a6SNicholas Bellinger return 0; 644c66ac9dbSNicholas Bellinger case MAINTENANCE_IN: 645ba539743SNicholas Bellinger switch (cdb[1] & 0x1f) { 646c66ac9dbSNicholas Bellinger case MI_REPORT_TARGET_PGS: 647c66ac9dbSNicholas Bellinger return 0; 648c66ac9dbSNicholas Bellinger default: 6491e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION); 650c66ac9dbSNicholas Bellinger return 1; 651c66ac9dbSNicholas Bellinger } 652c66ac9dbSNicholas Bellinger case REQUEST_SENSE: 653c66ac9dbSNicholas Bellinger case READ_BUFFER: 654c66ac9dbSNicholas Bellinger case WRITE_BUFFER: 655c66ac9dbSNicholas Bellinger return 0; 656c66ac9dbSNicholas Bellinger default: 6571e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION); 658c66ac9dbSNicholas Bellinger return 1; 659c66ac9dbSNicholas Bellinger } 660c66ac9dbSNicholas Bellinger 661c66ac9dbSNicholas Bellinger return 0; 662c66ac9dbSNicholas Bellinger } 663c66ac9dbSNicholas Bellinger 664c66ac9dbSNicholas Bellinger /* 665f1ae05d5SHannes Reinecke * return 1: Is used to signal LUN not accessible, and check condition/not ready 666c66ac9dbSNicholas Bellinger * return 0: Used to signal success 667f1ae05d5SHannes Reinecke * return -1: Used to signal failure, and invalid cdb field 668c66ac9dbSNicholas Bellinger */ 669de103c93SChristoph Hellwig sense_reason_t 670de103c93SChristoph Hellwig target_alua_state_check(struct se_cmd *cmd) 671c66ac9dbSNicholas Bellinger { 672c87fbd56SChristoph Hellwig struct se_device *dev = cmd->se_dev; 673c87fbd56SChristoph Hellwig unsigned char *cdb = cmd->t_task_cdb; 674e3d6f909SAndy Grover struct se_lun *lun = cmd->se_lun; 675c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 676c66ac9dbSNicholas Bellinger int out_alua_state, nonop_delay_msecs; 677c87fbd56SChristoph Hellwig 678c87fbd56SChristoph Hellwig if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) 679c87fbd56SChristoph Hellwig return 0; 68069088a04SBodo Stroesser if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA) 681c87fbd56SChristoph Hellwig return 0; 682c66ac9dbSNicholas Bellinger 683c66ac9dbSNicholas Bellinger /* 684c66ac9dbSNicholas Bellinger * First, check for a struct se_port specific secondary ALUA target port 685c66ac9dbSNicholas Bellinger * access state: OFFLINE 686c66ac9dbSNicholas Bellinger */ 687adf653f9SChristoph Hellwig if (atomic_read(&lun->lun_tg_pt_secondary_offline)) { 6886708bb27SAndy Grover pr_debug("ALUA: Got secondary offline status for local" 689c66ac9dbSNicholas Bellinger " target port\n"); 6901e3ab99dSPaul Bolle set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE); 6911e3ab99dSPaul Bolle return TCM_CHECK_CONDITION_NOT_READY; 692c66ac9dbSNicholas Bellinger } 693adf653f9SChristoph Hellwig 694adf653f9SChristoph Hellwig if (!lun->lun_tg_pt_gp) 69589c12cc9SNicholas Bellinger return 0; 69689c12cc9SNicholas Bellinger 697adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 698adf653f9SChristoph Hellwig tg_pt_gp = lun->lun_tg_pt_gp; 699d19c4643SMike Christie out_alua_state = tg_pt_gp->tg_pt_gp_alua_access_state; 700c66ac9dbSNicholas Bellinger nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; 701adf653f9SChristoph Hellwig 702adf653f9SChristoph Hellwig // XXX: keeps using tg_pt_gp witout reference after unlock 703adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 704c66ac9dbSNicholas Bellinger /* 70573f3bf51SHannes Reinecke * Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional 70625985edcSLucas De Marchi * statement so the compiler knows explicitly to check this case first. 707c66ac9dbSNicholas Bellinger * For the Optimized ALUA access state case, we want to process the 708c66ac9dbSNicholas Bellinger * incoming fabric cmd ASAP.. 709c66ac9dbSNicholas Bellinger */ 71073f3bf51SHannes Reinecke if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED) 711c66ac9dbSNicholas Bellinger return 0; 712c66ac9dbSNicholas Bellinger 713c66ac9dbSNicholas Bellinger switch (out_alua_state) { 714c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: 7151e3ab99dSPaul Bolle core_alua_state_nonoptimized(cmd, cdb, nonop_delay_msecs); 716c87fbd56SChristoph Hellwig break; 717c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_STANDBY: 7181e3ab99dSPaul Bolle if (core_alua_state_standby(cmd, cdb)) 7191e3ab99dSPaul Bolle return TCM_CHECK_CONDITION_NOT_READY; 720c87fbd56SChristoph Hellwig break; 721c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_UNAVAILABLE: 7221e3ab99dSPaul Bolle if (core_alua_state_unavailable(cmd, cdb)) 7231e3ab99dSPaul Bolle return TCM_CHECK_CONDITION_NOT_READY; 724c87fbd56SChristoph Hellwig break; 725c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_TRANSITION: 7261e3ab99dSPaul Bolle if (core_alua_state_transition(cmd, cdb)) 7271e3ab99dSPaul Bolle return TCM_CHECK_CONDITION_NOT_READY; 728c87fbd56SChristoph Hellwig break; 729c66094bfSHannes Reinecke case ALUA_ACCESS_STATE_LBA_DEPENDENT: 7301e3ab99dSPaul Bolle if (core_alua_state_lba_dependent(cmd, tg_pt_gp)) 7311e3ab99dSPaul Bolle return TCM_CHECK_CONDITION_NOT_READY; 732c66094bfSHannes Reinecke break; 733c66ac9dbSNicholas Bellinger /* 734c66ac9dbSNicholas Bellinger * OFFLINE is a secondary ALUA target port group access state, that is 735adf653f9SChristoph Hellwig * handled above with struct se_lun->lun_tg_pt_secondary_offline=1 736c66ac9dbSNicholas Bellinger */ 737c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_OFFLINE: 738c66ac9dbSNicholas Bellinger default: 7396708bb27SAndy Grover pr_err("Unknown ALUA access state: 0x%02x\n", 740c66ac9dbSNicholas Bellinger out_alua_state); 741de103c93SChristoph Hellwig return TCM_INVALID_CDB_FIELD; 742c66ac9dbSNicholas Bellinger } 743c66ac9dbSNicholas Bellinger 744de103c93SChristoph Hellwig return 0; 745c66ac9dbSNicholas Bellinger } 746c66ac9dbSNicholas Bellinger 747c66ac9dbSNicholas Bellinger /* 748125d0119SHannes Reinecke * Check implicit and explicit ALUA state change request. 749c66ac9dbSNicholas Bellinger */ 750de103c93SChristoph Hellwig static sense_reason_t 7511ca4d4faSMike Christie core_alua_check_transition(int state, int valid, int *primary, int explicit) 752c66ac9dbSNicholas Bellinger { 753c66ac9dbSNicholas Bellinger /* 754c66ac9dbSNicholas Bellinger * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are 755c66ac9dbSNicholas Bellinger * defined as primary target port asymmetric access states. 756c66ac9dbSNicholas Bellinger */ 757bb91c1a0SHannes Reinecke switch (state) { 758bb91c1a0SHannes Reinecke case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: 759bb91c1a0SHannes Reinecke if (!(valid & ALUA_AO_SUP)) 760bb91c1a0SHannes Reinecke goto not_supported; 761bb91c1a0SHannes Reinecke *primary = 1; 762bb91c1a0SHannes Reinecke break; 763bb91c1a0SHannes Reinecke case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: 764bb91c1a0SHannes Reinecke if (!(valid & ALUA_AN_SUP)) 765bb91c1a0SHannes Reinecke goto not_supported; 766bb91c1a0SHannes Reinecke *primary = 1; 767bb91c1a0SHannes Reinecke break; 768bb91c1a0SHannes Reinecke case ALUA_ACCESS_STATE_STANDBY: 769bb91c1a0SHannes Reinecke if (!(valid & ALUA_S_SUP)) 770bb91c1a0SHannes Reinecke goto not_supported; 771bb91c1a0SHannes Reinecke *primary = 1; 772bb91c1a0SHannes Reinecke break; 773bb91c1a0SHannes Reinecke case ALUA_ACCESS_STATE_UNAVAILABLE: 774bb91c1a0SHannes Reinecke if (!(valid & ALUA_U_SUP)) 775bb91c1a0SHannes Reinecke goto not_supported; 776c66ac9dbSNicholas Bellinger *primary = 1; 777c66ac9dbSNicholas Bellinger break; 778c66094bfSHannes Reinecke case ALUA_ACCESS_STATE_LBA_DEPENDENT: 779c66094bfSHannes Reinecke if (!(valid & ALUA_LBD_SUP)) 780c66094bfSHannes Reinecke goto not_supported; 781c66094bfSHannes Reinecke *primary = 1; 782c66094bfSHannes Reinecke break; 783c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_OFFLINE: 784c66ac9dbSNicholas Bellinger /* 785c66ac9dbSNicholas Bellinger * OFFLINE state is defined as a secondary target port 786c66ac9dbSNicholas Bellinger * asymmetric access state. 787c66ac9dbSNicholas Bellinger */ 788bb91c1a0SHannes Reinecke if (!(valid & ALUA_O_SUP)) 789bb91c1a0SHannes Reinecke goto not_supported; 790c66ac9dbSNicholas Bellinger *primary = 0; 791c66ac9dbSNicholas Bellinger break; 792bb91c1a0SHannes Reinecke case ALUA_ACCESS_STATE_TRANSITION: 7931ca4d4faSMike Christie if (!(valid & ALUA_T_SUP) || explicit) 794bb91c1a0SHannes Reinecke /* 7951ca4d4faSMike Christie * Transitioning is set internally and by tcmu daemon, 7961ca4d4faSMike Christie * and cannot be selected through a STPG. 797bb91c1a0SHannes Reinecke */ 798bb91c1a0SHannes Reinecke goto not_supported; 7991ca4d4faSMike Christie *primary = 0; 8001ca4d4faSMike Christie break; 801c66ac9dbSNicholas Bellinger default: 8026708bb27SAndy Grover pr_err("Unknown ALUA access state: 0x%02x\n", state); 803de103c93SChristoph Hellwig return TCM_INVALID_PARAMETER_LIST; 804c66ac9dbSNicholas Bellinger } 805c66ac9dbSNicholas Bellinger 806c66ac9dbSNicholas Bellinger return 0; 807bb91c1a0SHannes Reinecke 808bb91c1a0SHannes Reinecke not_supported: 809bb91c1a0SHannes Reinecke pr_err("ALUA access state %s not supported", 810bb91c1a0SHannes Reinecke core_alua_dump_state(state)); 811bb91c1a0SHannes Reinecke return TCM_INVALID_PARAMETER_LIST; 812c66ac9dbSNicholas Bellinger } 813c66ac9dbSNicholas Bellinger 814c66ac9dbSNicholas Bellinger static char *core_alua_dump_state(int state) 815c66ac9dbSNicholas Bellinger { 816c66ac9dbSNicholas Bellinger switch (state) { 81773f3bf51SHannes Reinecke case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: 818c66ac9dbSNicholas Bellinger return "Active/Optimized"; 819c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: 820c66ac9dbSNicholas Bellinger return "Active/NonOptimized"; 821c66094bfSHannes Reinecke case ALUA_ACCESS_STATE_LBA_DEPENDENT: 822c66094bfSHannes Reinecke return "LBA Dependent"; 823c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_STANDBY: 824c66ac9dbSNicholas Bellinger return "Standby"; 825c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_UNAVAILABLE: 826c66ac9dbSNicholas Bellinger return "Unavailable"; 827c66ac9dbSNicholas Bellinger case ALUA_ACCESS_STATE_OFFLINE: 828c66ac9dbSNicholas Bellinger return "Offline"; 829bb91c1a0SHannes Reinecke case ALUA_ACCESS_STATE_TRANSITION: 830bb91c1a0SHannes Reinecke return "Transitioning"; 831c66ac9dbSNicholas Bellinger default: 832c66ac9dbSNicholas Bellinger return "Unknown"; 833c66ac9dbSNicholas Bellinger } 834c66ac9dbSNicholas Bellinger 835c66ac9dbSNicholas Bellinger return NULL; 836c66ac9dbSNicholas Bellinger } 837c66ac9dbSNicholas Bellinger 838c66ac9dbSNicholas Bellinger char *core_alua_dump_status(int status) 839c66ac9dbSNicholas Bellinger { 840c66ac9dbSNicholas Bellinger switch (status) { 841c66ac9dbSNicholas Bellinger case ALUA_STATUS_NONE: 842c66ac9dbSNicholas Bellinger return "None"; 843125d0119SHannes Reinecke case ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG: 844125d0119SHannes Reinecke return "Altered by Explicit STPG"; 845125d0119SHannes Reinecke case ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA: 846125d0119SHannes Reinecke return "Altered by Implicit ALUA"; 847c66ac9dbSNicholas Bellinger default: 848c66ac9dbSNicholas Bellinger return "Unknown"; 849c66ac9dbSNicholas Bellinger } 850c66ac9dbSNicholas Bellinger 851c66ac9dbSNicholas Bellinger return NULL; 852c66ac9dbSNicholas Bellinger } 853c66ac9dbSNicholas Bellinger 854c66ac9dbSNicholas Bellinger /* 855c66ac9dbSNicholas Bellinger * Used by fabric modules to determine when we need to delay processing 856c66ac9dbSNicholas Bellinger * for the Active/NonOptimized paths.. 857c66ac9dbSNicholas Bellinger */ 858c66ac9dbSNicholas Bellinger int core_alua_check_nonop_delay( 859c66ac9dbSNicholas Bellinger struct se_cmd *cmd) 860c66ac9dbSNicholas Bellinger { 861c66ac9dbSNicholas Bellinger if (!(cmd->se_cmd_flags & SCF_ALUA_NON_OPTIMIZED)) 862c66ac9dbSNicholas Bellinger return 0; 863c66ac9dbSNicholas Bellinger /* 864c66ac9dbSNicholas Bellinger * The ALUA Active/NonOptimized access state delay can be disabled 865c66ac9dbSNicholas Bellinger * in via configfs with a value of zero 866c66ac9dbSNicholas Bellinger */ 8676708bb27SAndy Grover if (!cmd->alua_nonop_delay) 868c66ac9dbSNicholas Bellinger return 0; 869c66ac9dbSNicholas Bellinger /* 870c66ac9dbSNicholas Bellinger * struct se_cmd->alua_nonop_delay gets set by a target port group 871c66ac9dbSNicholas Bellinger * defined interval in core_alua_state_nonoptimized() 872c66ac9dbSNicholas Bellinger */ 873c66ac9dbSNicholas Bellinger msleep_interruptible(cmd->alua_nonop_delay); 874c66ac9dbSNicholas Bellinger return 0; 875c66ac9dbSNicholas Bellinger } 876c66ac9dbSNicholas Bellinger EXPORT_SYMBOL(core_alua_check_nonop_delay); 877c66ac9dbSNicholas Bellinger 878c66ac9dbSNicholas Bellinger static int core_alua_write_tpg_metadata( 879c66ac9dbSNicholas Bellinger const char *path, 880c66ac9dbSNicholas Bellinger unsigned char *md_buf, 881c66ac9dbSNicholas Bellinger u32 md_buf_len) 882c66ac9dbSNicholas Bellinger { 8830e9b10a9SAl Viro struct file *file = filp_open(path, O_RDWR | O_CREAT | O_TRUNC, 0600); 884e13ec939SChristoph Hellwig loff_t pos = 0; 8850e9b10a9SAl Viro int ret; 886c66ac9dbSNicholas Bellinger 8870e9b10a9SAl Viro if (IS_ERR(file)) { 8880e9b10a9SAl Viro pr_err("filp_open(%s) for ALUA metadata failed\n", path); 889c66ac9dbSNicholas Bellinger return -ENODEV; 890c66ac9dbSNicholas Bellinger } 891e13ec939SChristoph Hellwig ret = kernel_write(file, md_buf, md_buf_len, &pos); 8920e9b10a9SAl Viro if (ret < 0) 8936708bb27SAndy Grover pr_err("Error writing ALUA metadata file: %s\n", path); 8940e9b10a9SAl Viro fput(file); 895f730f915SGera Kazakov return (ret < 0) ? -EIO : 0; 896c66ac9dbSNicholas Bellinger } 897c66ac9dbSNicholas Bellinger 898c66ac9dbSNicholas Bellinger static int core_alua_update_tpg_primary_metadata( 8999c6e164cSHannes Reinecke struct t10_alua_tg_pt_gp *tg_pt_gp) 900c66ac9dbSNicholas Bellinger { 9011e0b9403SHannes Reinecke unsigned char *md_buf; 9020fd97ccfSChristoph Hellwig struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn; 90355435badSDavid Disseldorp char *path; 9041e0b9403SHannes Reinecke int len, rc; 9051e0b9403SHannes Reinecke 906618baaf7SBart Van Assche lockdep_assert_held(&tg_pt_gp->tg_pt_gp_transition_mutex); 907618baaf7SBart Van Assche 9081e0b9403SHannes Reinecke md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); 9091e0b9403SHannes Reinecke if (!md_buf) { 9101e0b9403SHannes Reinecke pr_err("Unable to allocate buf for ALUA metadata\n"); 9111e0b9403SHannes Reinecke return -ENOMEM; 9121e0b9403SHannes Reinecke } 913c66ac9dbSNicholas Bellinger 9141e0b9403SHannes Reinecke len = snprintf(md_buf, ALUA_MD_BUF_LEN, 915c66ac9dbSNicholas Bellinger "tg_pt_gp_id=%hu\n" 916c66ac9dbSNicholas Bellinger "alua_access_state=0x%02x\n" 917c66ac9dbSNicholas Bellinger "alua_access_status=0x%02x\n", 9189c6e164cSHannes Reinecke tg_pt_gp->tg_pt_gp_id, 919d19c4643SMike Christie tg_pt_gp->tg_pt_gp_alua_access_state, 920c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_alua_access_status); 921c66ac9dbSNicholas Bellinger 92255435badSDavid Disseldorp rc = -ENOMEM; 92355435badSDavid Disseldorp path = kasprintf(GFP_KERNEL, "%s/alua/tpgs_%s/%s", db_root, 92455435badSDavid Disseldorp &wwn->unit_serial[0], 925c66ac9dbSNicholas Bellinger config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item)); 92655435badSDavid Disseldorp if (path) { 9271e0b9403SHannes Reinecke rc = core_alua_write_tpg_metadata(path, md_buf, len); 92855435badSDavid Disseldorp kfree(path); 92955435badSDavid Disseldorp } 9301e0b9403SHannes Reinecke kfree(md_buf); 9311e0b9403SHannes Reinecke return rc; 932c66ac9dbSNicholas Bellinger } 933c66ac9dbSNicholas Bellinger 934ee8c07d0SHannes Reinecke static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) 935c66ac9dbSNicholas Bellinger { 936c66ac9dbSNicholas Bellinger struct se_dev_entry *se_deve; 937adf653f9SChristoph Hellwig struct se_lun *lun; 938c66ac9dbSNicholas Bellinger struct se_lun_acl *lacl; 939c66ac9dbSNicholas Bellinger 940c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 941adf653f9SChristoph Hellwig list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, 942adf653f9SChristoph Hellwig lun_tg_pt_gp_link) { 943c66ac9dbSNicholas Bellinger /* 944c66ac9dbSNicholas Bellinger * After an implicit target port asymmetric access state 945c66ac9dbSNicholas Bellinger * change, a device server shall establish a unit attention 946c66ac9dbSNicholas Bellinger * condition for the initiator port associated with every I_T 947c66ac9dbSNicholas Bellinger * nexus with the additional sense code set to ASYMMETRIC 948f1ae05d5SHannes Reinecke * ACCESS STATE CHANGED. 949c66ac9dbSNicholas Bellinger * 950c66ac9dbSNicholas Bellinger * After an explicit target port asymmetric access state 951c66ac9dbSNicholas Bellinger * change, a device server shall establish a unit attention 952c66ac9dbSNicholas Bellinger * condition with the additional sense code set to ASYMMETRIC 953c66ac9dbSNicholas Bellinger * ACCESS STATE CHANGED for the initiator port associated with 954c66ac9dbSNicholas Bellinger * every I_T nexus other than the I_T nexus on which the SET 955c66ac9dbSNicholas Bellinger * TARGET PORT GROUPS command 956c66ac9dbSNicholas Bellinger */ 9579e37d042SNicholas Bellinger if (!percpu_ref_tryget_live(&lun->lun_ref)) 9589e37d042SNicholas Bellinger continue; 959c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 960c66ac9dbSNicholas Bellinger 9611adff1b3SNicholas Bellinger spin_lock(&lun->lun_deve_lock); 962adf653f9SChristoph Hellwig list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { 96329a05deeSNicholas Bellinger lacl = rcu_dereference_check(se_deve->se_lun_acl, 964adf653f9SChristoph Hellwig lockdep_is_held(&lun->lun_deve_lock)); 965c66ac9dbSNicholas Bellinger 966c51c8e7bSHannes Reinecke /* 967c51c8e7bSHannes Reinecke * spc4r37 p.242: 968c51c8e7bSHannes Reinecke * After an explicit target port asymmetric access 969c51c8e7bSHannes Reinecke * state change, a device server shall establish a 970c51c8e7bSHannes Reinecke * unit attention condition with the additional sense 971c51c8e7bSHannes Reinecke * code set to ASYMMETRIC ACCESS STATE CHANGED for 972c51c8e7bSHannes Reinecke * the initiator port associated with every I_T nexus 973c51c8e7bSHannes Reinecke * other than the I_T nexus on which the SET TARGET 974c51c8e7bSHannes Reinecke * PORT GROUPS command was received. 975c51c8e7bSHannes Reinecke */ 9769c6e164cSHannes Reinecke if ((tg_pt_gp->tg_pt_gp_alua_access_status == 9779c6e164cSHannes Reinecke ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && 978adf653f9SChristoph Hellwig (tg_pt_gp->tg_pt_gp_alua_lun != NULL) && 979adf653f9SChristoph Hellwig (tg_pt_gp->tg_pt_gp_alua_lun == lun)) 980c66ac9dbSNicholas Bellinger continue; 981c66ac9dbSNicholas Bellinger 982c66ac9dbSNicholas Bellinger /* 983c66ac9dbSNicholas Bellinger * se_deve->se_lun_acl pointer may be NULL for a 984c66ac9dbSNicholas Bellinger * entry created without explicit Node+MappedLUN ACLs 985c66ac9dbSNicholas Bellinger */ 986c51c8e7bSHannes Reinecke if (lacl && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && 987c51c8e7bSHannes Reinecke (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl)) 988c66ac9dbSNicholas Bellinger continue; 989c66ac9dbSNicholas Bellinger 990c51c8e7bSHannes Reinecke core_scsi3_ua_allocate(se_deve, 0x2A, 991c66ac9dbSNicholas Bellinger ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); 992c66ac9dbSNicholas Bellinger } 9931adff1b3SNicholas Bellinger spin_unlock(&lun->lun_deve_lock); 994c66ac9dbSNicholas Bellinger 995c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 9969e37d042SNicholas Bellinger percpu_ref_put(&lun->lun_ref); 997c66ac9dbSNicholas Bellinger } 998c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 999ee8c07d0SHannes Reinecke } 1000ee8c07d0SHannes Reinecke 1001d19c4643SMike Christie static int core_alua_do_transition_tg_pt( 1002d19c4643SMike Christie struct t10_alua_tg_pt_gp *tg_pt_gp, 1003d19c4643SMike Christie int new_state, 1004d19c4643SMike Christie int explicit) 1005ee8c07d0SHannes Reinecke { 1006d19c4643SMike Christie int prev_state; 1007d19c4643SMike Christie 1008d19c4643SMike Christie mutex_lock(&tg_pt_gp->tg_pt_gp_transition_mutex); 1009d19c4643SMike Christie /* Nothing to be done here */ 1010d19c4643SMike Christie if (tg_pt_gp->tg_pt_gp_alua_access_state == new_state) { 1011d19c4643SMike Christie mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex); 1012d19c4643SMike Christie return 0; 1013d19c4643SMike Christie } 1014d19c4643SMike Christie 1015d19c4643SMike Christie if (explicit && new_state == ALUA_ACCESS_STATE_TRANSITION) { 1016d19c4643SMike Christie mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex); 1017d19c4643SMike Christie return -EAGAIN; 1018d19c4643SMike Christie } 1019d19c4643SMike Christie 1020d19c4643SMike Christie /* 1021d19c4643SMike Christie * Save the old primary ALUA access state, and set the current state 1022d19c4643SMike Christie * to ALUA_ACCESS_STATE_TRANSITION. 1023d19c4643SMike Christie */ 1024d19c4643SMike Christie prev_state = tg_pt_gp->tg_pt_gp_alua_access_state; 1025d19c4643SMike Christie tg_pt_gp->tg_pt_gp_alua_access_state = ALUA_ACCESS_STATE_TRANSITION; 1026d19c4643SMike Christie tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ? 1027d19c4643SMike Christie ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : 1028d19c4643SMike Christie ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; 1029d19c4643SMike Christie 1030d19c4643SMike Christie core_alua_queue_state_change_ua(tg_pt_gp); 1031d19c4643SMike Christie 1032d19c4643SMike Christie if (new_state == ALUA_ACCESS_STATE_TRANSITION) { 1033d19c4643SMike Christie mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex); 1034d19c4643SMike Christie return 0; 1035d19c4643SMike Christie } 1036d19c4643SMike Christie 1037d19c4643SMike Christie /* 1038d19c4643SMike Christie * Check for the optional ALUA primary state transition delay 1039d19c4643SMike Christie */ 1040d19c4643SMike Christie if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0) 1041d19c4643SMike Christie msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs); 1042d19c4643SMike Christie 1043d19c4643SMike Christie /* 1044d19c4643SMike Christie * Set the current primary ALUA access state to the requested new state 1045d19c4643SMike Christie */ 1046d19c4643SMike Christie tg_pt_gp->tg_pt_gp_alua_access_state = new_state; 1047ee8c07d0SHannes Reinecke 1048c66ac9dbSNicholas Bellinger /* 1049c66ac9dbSNicholas Bellinger * Update the ALUA metadata buf that has been allocated in 1050c66ac9dbSNicholas Bellinger * core_alua_do_port_transition(), this metadata will be written 1051c66ac9dbSNicholas Bellinger * to struct file. 1052c66ac9dbSNicholas Bellinger * 1053c66ac9dbSNicholas Bellinger * Note that there is the case where we do not want to update the 1054c66ac9dbSNicholas Bellinger * metadata when the saved metadata is being parsed in userspace 1055c66ac9dbSNicholas Bellinger * when setting the existing port access state and access status. 1056c66ac9dbSNicholas Bellinger * 1057c66ac9dbSNicholas Bellinger * Also note that the failure to write out the ALUA metadata to 1058c66ac9dbSNicholas Bellinger * struct file does NOT affect the actual ALUA transition. 1059c66ac9dbSNicholas Bellinger */ 1060c66ac9dbSNicholas Bellinger if (tg_pt_gp->tg_pt_gp_write_metadata) { 10619c6e164cSHannes Reinecke core_alua_update_tpg_primary_metadata(tg_pt_gp); 1062c66ac9dbSNicholas Bellinger } 1063c66ac9dbSNicholas Bellinger 10646708bb27SAndy Grover pr_debug("Successful %s ALUA transition TG PT Group: %s ID: %hu" 1065125d0119SHannes Reinecke " from primary access state %s to %s\n", (explicit) ? "explicit" : 1066125d0119SHannes Reinecke "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), 1067dfbce75aSHannes Reinecke tg_pt_gp->tg_pt_gp_id, 1068d19c4643SMike Christie core_alua_dump_state(prev_state), 1069d19c4643SMike Christie core_alua_dump_state(new_state)); 1070ee8c07d0SHannes Reinecke 1071ee8c07d0SHannes Reinecke core_alua_queue_state_change_ua(tg_pt_gp); 1072ee8c07d0SHannes Reinecke 1073d19c4643SMike Christie mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex); 1074c66ac9dbSNicholas Bellinger return 0; 1075c66ac9dbSNicholas Bellinger } 1076c66ac9dbSNicholas Bellinger 1077c66ac9dbSNicholas Bellinger int core_alua_do_port_transition( 1078c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *l_tg_pt_gp, 1079c66ac9dbSNicholas Bellinger struct se_device *l_dev, 1080adf653f9SChristoph Hellwig struct se_lun *l_lun, 1081c66ac9dbSNicholas Bellinger struct se_node_acl *l_nacl, 1082c66ac9dbSNicholas Bellinger int new_state, 1083125d0119SHannes Reinecke int explicit) 1084c66ac9dbSNicholas Bellinger { 1085c66ac9dbSNicholas Bellinger struct se_device *dev; 1086c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp; 1087c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; 1088c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 10899c6e164cSHannes Reinecke int primary, valid_states, rc = 0; 1090c66ac9dbSNicholas Bellinger 109169088a04SBodo Stroesser if (l_dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA) 10920a414572SMike Christie return -ENODEV; 10930a414572SMike Christie 1094bb91c1a0SHannes Reinecke valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; 10951ca4d4faSMike Christie if (core_alua_check_transition(new_state, valid_states, &primary, 10961ca4d4faSMike Christie explicit) != 0) 1097c66ac9dbSNicholas Bellinger return -EINVAL; 1098c66ac9dbSNicholas Bellinger 1099c66ac9dbSNicholas Bellinger local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem; 1100c66ac9dbSNicholas Bellinger spin_lock(&local_lu_gp_mem->lu_gp_mem_lock); 1101c66ac9dbSNicholas Bellinger lu_gp = local_lu_gp_mem->lu_gp; 1102c66ac9dbSNicholas Bellinger atomic_inc(&lu_gp->lu_gp_ref_cnt); 1103c66ac9dbSNicholas Bellinger spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock); 1104c66ac9dbSNicholas Bellinger /* 1105c66ac9dbSNicholas Bellinger * For storage objects that are members of the 'default_lu_gp', 1106c66ac9dbSNicholas Bellinger * we only do transition on the passed *l_tp_pt_gp, and not 1107c66ac9dbSNicholas Bellinger * on all of the matching target port groups IDs in default_lu_gp. 1108c66ac9dbSNicholas Bellinger */ 11096708bb27SAndy Grover if (!lu_gp->lu_gp_id) { 1110c66ac9dbSNicholas Bellinger /* 1111c66ac9dbSNicholas Bellinger * core_alua_do_transition_tg_pt() will always return 1112c66ac9dbSNicholas Bellinger * success. 1113c66ac9dbSNicholas Bellinger */ 1114adf653f9SChristoph Hellwig l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun; 11159c6e164cSHannes Reinecke l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; 11169c6e164cSHannes Reinecke rc = core_alua_do_transition_tg_pt(l_tg_pt_gp, 11171e0b9403SHannes Reinecke new_state, explicit); 111833940d09SJoern Engel atomic_dec_mb(&lu_gp->lu_gp_ref_cnt); 11199c6e164cSHannes Reinecke return rc; 1120c66ac9dbSNicholas Bellinger } 1121c66ac9dbSNicholas Bellinger /* 1122c66ac9dbSNicholas Bellinger * For all other LU groups aside from 'default_lu_gp', walk all of 1123c66ac9dbSNicholas Bellinger * the associated storage objects looking for a matching target port 1124c66ac9dbSNicholas Bellinger * group ID from the local target port group. 1125c66ac9dbSNicholas Bellinger */ 1126c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 1127c66ac9dbSNicholas Bellinger list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, 1128c66ac9dbSNicholas Bellinger lu_gp_mem_list) { 1129c66ac9dbSNicholas Bellinger 1130c66ac9dbSNicholas Bellinger dev = lu_gp_mem->lu_gp_mem_dev; 113133940d09SJoern Engel atomic_inc_mb(&lu_gp_mem->lu_gp_mem_ref_cnt); 1132c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1133c66ac9dbSNicholas Bellinger 11340fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 1135c66ac9dbSNicholas Bellinger list_for_each_entry(tg_pt_gp, 11360fd97ccfSChristoph Hellwig &dev->t10_alua.tg_pt_gps_list, 1137c66ac9dbSNicholas Bellinger tg_pt_gp_list) { 1138c66ac9dbSNicholas Bellinger 11396708bb27SAndy Grover if (!tg_pt_gp->tg_pt_gp_valid_id) 1140c66ac9dbSNicholas Bellinger continue; 1141c66ac9dbSNicholas Bellinger /* 1142c66ac9dbSNicholas Bellinger * If the target behavior port asymmetric access state 1143f1ae05d5SHannes Reinecke * is changed for any target port group accessible via 1144c66ac9dbSNicholas Bellinger * a logical unit within a LU group, the target port 1145c66ac9dbSNicholas Bellinger * behavior group asymmetric access states for the same 1146c66ac9dbSNicholas Bellinger * target port group accessible via other logical units 1147c66ac9dbSNicholas Bellinger * in that LU group will also change. 1148c66ac9dbSNicholas Bellinger */ 1149c66ac9dbSNicholas Bellinger if (l_tg_pt_gp->tg_pt_gp_id != tg_pt_gp->tg_pt_gp_id) 1150c66ac9dbSNicholas Bellinger continue; 1151c66ac9dbSNicholas Bellinger 1152c66ac9dbSNicholas Bellinger if (l_tg_pt_gp == tg_pt_gp) { 1153adf653f9SChristoph Hellwig tg_pt_gp->tg_pt_gp_alua_lun = l_lun; 11549c6e164cSHannes Reinecke tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; 1155c66ac9dbSNicholas Bellinger } else { 1156adf653f9SChristoph Hellwig tg_pt_gp->tg_pt_gp_alua_lun = NULL; 11579c6e164cSHannes Reinecke tg_pt_gp->tg_pt_gp_alua_nacl = NULL; 1158c66ac9dbSNicholas Bellinger } 115933940d09SJoern Engel atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); 11600fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1161c66ac9dbSNicholas Bellinger /* 1162c66ac9dbSNicholas Bellinger * core_alua_do_transition_tg_pt() will always return 1163c66ac9dbSNicholas Bellinger * success. 1164c66ac9dbSNicholas Bellinger */ 11659c6e164cSHannes Reinecke rc = core_alua_do_transition_tg_pt(tg_pt_gp, 11669c6e164cSHannes Reinecke new_state, explicit); 1167c66ac9dbSNicholas Bellinger 11680fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 116933940d09SJoern Engel atomic_dec_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); 11709c6e164cSHannes Reinecke if (rc) 11719c6e164cSHannes Reinecke break; 1172c66ac9dbSNicholas Bellinger } 11730fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1174c66ac9dbSNicholas Bellinger 1175c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 117633940d09SJoern Engel atomic_dec_mb(&lu_gp_mem->lu_gp_mem_ref_cnt); 1177c66ac9dbSNicholas Bellinger } 1178c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1179c66ac9dbSNicholas Bellinger 11809c6e164cSHannes Reinecke if (!rc) { 11816708bb27SAndy Grover pr_debug("Successfully processed LU Group: %s all ALUA TG PT" 1182c66ac9dbSNicholas Bellinger " Group IDs: %hu %s transition to primary state: %s\n", 1183c66ac9dbSNicholas Bellinger config_item_name(&lu_gp->lu_gp_group.cg_item), 11849c6e164cSHannes Reinecke l_tg_pt_gp->tg_pt_gp_id, 11859c6e164cSHannes Reinecke (explicit) ? "explicit" : "implicit", 1186c66ac9dbSNicholas Bellinger core_alua_dump_state(new_state)); 11879c6e164cSHannes Reinecke } 1188c66ac9dbSNicholas Bellinger 118933940d09SJoern Engel atomic_dec_mb(&lu_gp->lu_gp_ref_cnt); 11909c6e164cSHannes Reinecke return rc; 1191c66ac9dbSNicholas Bellinger } 1192c66ac9dbSNicholas Bellinger 1193adf653f9SChristoph Hellwig static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun) 1194c66ac9dbSNicholas Bellinger { 1195adf653f9SChristoph Hellwig struct se_portal_group *se_tpg = lun->lun_tpg; 11961e0b9403SHannes Reinecke unsigned char *md_buf; 119755435badSDavid Disseldorp char *path; 11981e0b9403SHannes Reinecke int len, rc; 11991e0b9403SHannes Reinecke 1200adf653f9SChristoph Hellwig mutex_lock(&lun->lun_tg_pt_md_mutex); 1201adf653f9SChristoph Hellwig 12021e0b9403SHannes Reinecke md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); 12031e0b9403SHannes Reinecke if (!md_buf) { 12041e0b9403SHannes Reinecke pr_err("Unable to allocate buf for ALUA metadata\n"); 1205adf653f9SChristoph Hellwig rc = -ENOMEM; 1206adf653f9SChristoph Hellwig goto out_unlock; 12071e0b9403SHannes Reinecke } 1208c66ac9dbSNicholas Bellinger 12091e0b9403SHannes Reinecke len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n" 1210c66ac9dbSNicholas Bellinger "alua_tg_pt_status=0x%02x\n", 1211adf653f9SChristoph Hellwig atomic_read(&lun->lun_tg_pt_secondary_offline), 1212adf653f9SChristoph Hellwig lun->lun_tg_pt_secondary_stat); 1213c66ac9dbSNicholas Bellinger 121455435badSDavid Disseldorp if (se_tpg->se_tpg_tfo->tpg_get_tag != NULL) { 121555435badSDavid Disseldorp path = kasprintf(GFP_KERNEL, "%s/alua/%s/%s+%hu/lun_%llu", 121630c7ca93SDavid Disseldorp db_root, se_tpg->se_tpg_tfo->fabric_name, 121755435badSDavid Disseldorp se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg), 121855435badSDavid Disseldorp se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg), 1219adf653f9SChristoph Hellwig lun->unpacked_lun); 122055435badSDavid Disseldorp } else { 122155435badSDavid Disseldorp path = kasprintf(GFP_KERNEL, "%s/alua/%s/%s/lun_%llu", 122230c7ca93SDavid Disseldorp db_root, se_tpg->se_tpg_tfo->fabric_name, 122355435badSDavid Disseldorp se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg), 122455435badSDavid Disseldorp lun->unpacked_lun); 122555435badSDavid Disseldorp } 122655435badSDavid Disseldorp if (!path) { 122755435badSDavid Disseldorp rc = -ENOMEM; 122855435badSDavid Disseldorp goto out_free; 122955435badSDavid Disseldorp } 1230c66ac9dbSNicholas Bellinger 12311e0b9403SHannes Reinecke rc = core_alua_write_tpg_metadata(path, md_buf, len); 123255435badSDavid Disseldorp kfree(path); 123355435badSDavid Disseldorp out_free: 12341e0b9403SHannes Reinecke kfree(md_buf); 1235adf653f9SChristoph Hellwig out_unlock: 1236adf653f9SChristoph Hellwig mutex_unlock(&lun->lun_tg_pt_md_mutex); 12371e0b9403SHannes Reinecke return rc; 1238c66ac9dbSNicholas Bellinger } 1239c66ac9dbSNicholas Bellinger 1240c66ac9dbSNicholas Bellinger static int core_alua_set_tg_pt_secondary_state( 1241adf653f9SChristoph Hellwig struct se_lun *lun, 1242125d0119SHannes Reinecke int explicit, 1243c66ac9dbSNicholas Bellinger int offline) 1244c66ac9dbSNicholas Bellinger { 1245c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 1246c66ac9dbSNicholas Bellinger int trans_delay_msecs; 1247c66ac9dbSNicholas Bellinger 1248adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 1249adf653f9SChristoph Hellwig tg_pt_gp = lun->lun_tg_pt_gp; 12506708bb27SAndy Grover if (!tg_pt_gp) { 1251adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 12526708bb27SAndy Grover pr_err("Unable to complete secondary state" 1253c66ac9dbSNicholas Bellinger " transition\n"); 1254e3d6f909SAndy Grover return -EINVAL; 1255c66ac9dbSNicholas Bellinger } 1256c66ac9dbSNicholas Bellinger trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs; 1257c66ac9dbSNicholas Bellinger /* 1258c66ac9dbSNicholas Bellinger * Set the secondary ALUA target port access state to OFFLINE 1259adf653f9SChristoph Hellwig * or release the previously secondary state for struct se_lun 1260c66ac9dbSNicholas Bellinger */ 1261c66ac9dbSNicholas Bellinger if (offline) 1262adf653f9SChristoph Hellwig atomic_set(&lun->lun_tg_pt_secondary_offline, 1); 1263c66ac9dbSNicholas Bellinger else 1264adf653f9SChristoph Hellwig atomic_set(&lun->lun_tg_pt_secondary_offline, 0); 1265c66ac9dbSNicholas Bellinger 1266adf653f9SChristoph Hellwig lun->lun_tg_pt_secondary_stat = (explicit) ? 1267125d0119SHannes Reinecke ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : 1268125d0119SHannes Reinecke ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; 1269c66ac9dbSNicholas Bellinger 12706708bb27SAndy Grover pr_debug("Successful %s ALUA transition TG PT Group: %s ID: %hu" 1271125d0119SHannes Reinecke " to secondary access state: %s\n", (explicit) ? "explicit" : 1272125d0119SHannes Reinecke "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), 1273c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE"); 1274c66ac9dbSNicholas Bellinger 1275adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 1276c66ac9dbSNicholas Bellinger /* 1277c66ac9dbSNicholas Bellinger * Do the optional transition delay after we set the secondary 1278c66ac9dbSNicholas Bellinger * ALUA access state. 1279c66ac9dbSNicholas Bellinger */ 1280c66ac9dbSNicholas Bellinger if (trans_delay_msecs != 0) 1281c66ac9dbSNicholas Bellinger msleep_interruptible(trans_delay_msecs); 1282c66ac9dbSNicholas Bellinger /* 1283c66ac9dbSNicholas Bellinger * See if we need to update the ALUA fabric port metadata for 1284c66ac9dbSNicholas Bellinger * secondary state and status 1285c66ac9dbSNicholas Bellinger */ 1286adf653f9SChristoph Hellwig if (lun->lun_tg_pt_secondary_write_md) 1287adf653f9SChristoph Hellwig core_alua_update_tpg_secondary_metadata(lun); 1288c66ac9dbSNicholas Bellinger 1289c66ac9dbSNicholas Bellinger return 0; 1290c66ac9dbSNicholas Bellinger } 1291c66ac9dbSNicholas Bellinger 1292229d4f11SHannes Reinecke struct t10_alua_lba_map * 1293229d4f11SHannes Reinecke core_alua_allocate_lba_map(struct list_head *list, 1294229d4f11SHannes Reinecke u64 first_lba, u64 last_lba) 1295229d4f11SHannes Reinecke { 1296229d4f11SHannes Reinecke struct t10_alua_lba_map *lba_map; 1297229d4f11SHannes Reinecke 1298229d4f11SHannes Reinecke lba_map = kmem_cache_zalloc(t10_alua_lba_map_cache, GFP_KERNEL); 1299229d4f11SHannes Reinecke if (!lba_map) { 1300229d4f11SHannes Reinecke pr_err("Unable to allocate struct t10_alua_lba_map\n"); 1301229d4f11SHannes Reinecke return ERR_PTR(-ENOMEM); 1302229d4f11SHannes Reinecke } 1303229d4f11SHannes Reinecke INIT_LIST_HEAD(&lba_map->lba_map_mem_list); 1304229d4f11SHannes Reinecke lba_map->lba_map_first_lba = first_lba; 1305229d4f11SHannes Reinecke lba_map->lba_map_last_lba = last_lba; 1306229d4f11SHannes Reinecke 1307229d4f11SHannes Reinecke list_add_tail(&lba_map->lba_map_list, list); 1308229d4f11SHannes Reinecke return lba_map; 1309229d4f11SHannes Reinecke } 1310229d4f11SHannes Reinecke 1311229d4f11SHannes Reinecke int 1312229d4f11SHannes Reinecke core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *lba_map, 1313229d4f11SHannes Reinecke int pg_id, int state) 1314229d4f11SHannes Reinecke { 1315229d4f11SHannes Reinecke struct t10_alua_lba_map_member *lba_map_mem; 1316229d4f11SHannes Reinecke 1317229d4f11SHannes Reinecke list_for_each_entry(lba_map_mem, &lba_map->lba_map_mem_list, 1318229d4f11SHannes Reinecke lba_map_mem_list) { 1319229d4f11SHannes Reinecke if (lba_map_mem->lba_map_mem_alua_pg_id == pg_id) { 1320229d4f11SHannes Reinecke pr_err("Duplicate pg_id %d in lba_map\n", pg_id); 1321229d4f11SHannes Reinecke return -EINVAL; 1322229d4f11SHannes Reinecke } 1323229d4f11SHannes Reinecke } 1324229d4f11SHannes Reinecke 1325229d4f11SHannes Reinecke lba_map_mem = kmem_cache_zalloc(t10_alua_lba_map_mem_cache, GFP_KERNEL); 1326229d4f11SHannes Reinecke if (!lba_map_mem) { 1327229d4f11SHannes Reinecke pr_err("Unable to allocate struct t10_alua_lba_map_mem\n"); 1328229d4f11SHannes Reinecke return -ENOMEM; 1329229d4f11SHannes Reinecke } 1330229d4f11SHannes Reinecke lba_map_mem->lba_map_mem_alua_state = state; 1331229d4f11SHannes Reinecke lba_map_mem->lba_map_mem_alua_pg_id = pg_id; 1332229d4f11SHannes Reinecke 1333229d4f11SHannes Reinecke list_add_tail(&lba_map_mem->lba_map_mem_list, 1334229d4f11SHannes Reinecke &lba_map->lba_map_mem_list); 1335229d4f11SHannes Reinecke return 0; 1336229d4f11SHannes Reinecke } 1337229d4f11SHannes Reinecke 1338229d4f11SHannes Reinecke void 1339229d4f11SHannes Reinecke core_alua_free_lba_map(struct list_head *lba_list) 1340229d4f11SHannes Reinecke { 1341229d4f11SHannes Reinecke struct t10_alua_lba_map *lba_map, *lba_map_tmp; 1342229d4f11SHannes Reinecke struct t10_alua_lba_map_member *lba_map_mem, *lba_map_mem_tmp; 1343229d4f11SHannes Reinecke 1344229d4f11SHannes Reinecke list_for_each_entry_safe(lba_map, lba_map_tmp, lba_list, 1345229d4f11SHannes Reinecke lba_map_list) { 1346229d4f11SHannes Reinecke list_for_each_entry_safe(lba_map_mem, lba_map_mem_tmp, 1347229d4f11SHannes Reinecke &lba_map->lba_map_mem_list, 1348229d4f11SHannes Reinecke lba_map_mem_list) { 1349229d4f11SHannes Reinecke list_del(&lba_map_mem->lba_map_mem_list); 1350229d4f11SHannes Reinecke kmem_cache_free(t10_alua_lba_map_mem_cache, 1351229d4f11SHannes Reinecke lba_map_mem); 1352229d4f11SHannes Reinecke } 1353229d4f11SHannes Reinecke list_del(&lba_map->lba_map_list); 1354229d4f11SHannes Reinecke kmem_cache_free(t10_alua_lba_map_cache, lba_map); 1355229d4f11SHannes Reinecke } 1356229d4f11SHannes Reinecke } 1357229d4f11SHannes Reinecke 1358229d4f11SHannes Reinecke void 1359229d4f11SHannes Reinecke core_alua_set_lba_map(struct se_device *dev, struct list_head *lba_map_list, 1360229d4f11SHannes Reinecke int segment_size, int segment_mult) 1361229d4f11SHannes Reinecke { 1362229d4f11SHannes Reinecke struct list_head old_lba_map_list; 1363229d4f11SHannes Reinecke struct t10_alua_tg_pt_gp *tg_pt_gp; 1364229d4f11SHannes Reinecke int activate = 0, supported; 1365229d4f11SHannes Reinecke 1366229d4f11SHannes Reinecke INIT_LIST_HEAD(&old_lba_map_list); 1367229d4f11SHannes Reinecke spin_lock(&dev->t10_alua.lba_map_lock); 1368229d4f11SHannes Reinecke dev->t10_alua.lba_map_segment_size = segment_size; 1369229d4f11SHannes Reinecke dev->t10_alua.lba_map_segment_multiplier = segment_mult; 1370229d4f11SHannes Reinecke list_splice_init(&dev->t10_alua.lba_map_list, &old_lba_map_list); 1371229d4f11SHannes Reinecke if (lba_map_list) { 1372229d4f11SHannes Reinecke list_splice_init(lba_map_list, &dev->t10_alua.lba_map_list); 1373229d4f11SHannes Reinecke activate = 1; 1374229d4f11SHannes Reinecke } 1375229d4f11SHannes Reinecke spin_unlock(&dev->t10_alua.lba_map_lock); 1376229d4f11SHannes Reinecke spin_lock(&dev->t10_alua.tg_pt_gps_lock); 1377229d4f11SHannes Reinecke list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, 1378229d4f11SHannes Reinecke tg_pt_gp_list) { 1379229d4f11SHannes Reinecke 1380229d4f11SHannes Reinecke if (!tg_pt_gp->tg_pt_gp_valid_id) 1381229d4f11SHannes Reinecke continue; 1382229d4f11SHannes Reinecke supported = tg_pt_gp->tg_pt_gp_alua_supported_states; 1383229d4f11SHannes Reinecke if (activate) 1384229d4f11SHannes Reinecke supported |= ALUA_LBD_SUP; 1385229d4f11SHannes Reinecke else 1386229d4f11SHannes Reinecke supported &= ~ALUA_LBD_SUP; 1387229d4f11SHannes Reinecke tg_pt_gp->tg_pt_gp_alua_supported_states = supported; 1388229d4f11SHannes Reinecke } 1389229d4f11SHannes Reinecke spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1390229d4f11SHannes Reinecke core_alua_free_lba_map(&old_lba_map_list); 1391229d4f11SHannes Reinecke } 1392229d4f11SHannes Reinecke 1393c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp * 1394c66ac9dbSNicholas Bellinger core_alua_allocate_lu_gp(const char *name, int def_group) 1395c66ac9dbSNicholas Bellinger { 1396c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp; 1397c66ac9dbSNicholas Bellinger 1398c66ac9dbSNicholas Bellinger lu_gp = kmem_cache_zalloc(t10_alua_lu_gp_cache, GFP_KERNEL); 13996708bb27SAndy Grover if (!lu_gp) { 14006708bb27SAndy Grover pr_err("Unable to allocate struct t10_alua_lu_gp\n"); 14016eab04a8SJustin P. Mattock return ERR_PTR(-ENOMEM); 1402c66ac9dbSNicholas Bellinger } 1403e3d6f909SAndy Grover INIT_LIST_HEAD(&lu_gp->lu_gp_node); 1404c66ac9dbSNicholas Bellinger INIT_LIST_HEAD(&lu_gp->lu_gp_mem_list); 1405c66ac9dbSNicholas Bellinger spin_lock_init(&lu_gp->lu_gp_lock); 1406c66ac9dbSNicholas Bellinger atomic_set(&lu_gp->lu_gp_ref_cnt, 0); 1407c66ac9dbSNicholas Bellinger 1408c66ac9dbSNicholas Bellinger if (def_group) { 1409e3d6f909SAndy Grover lu_gp->lu_gp_id = alua_lu_gps_counter++; 1410c66ac9dbSNicholas Bellinger lu_gp->lu_gp_valid_id = 1; 1411e3d6f909SAndy Grover alua_lu_gps_count++; 1412c66ac9dbSNicholas Bellinger } 1413c66ac9dbSNicholas Bellinger 1414c66ac9dbSNicholas Bellinger return lu_gp; 1415c66ac9dbSNicholas Bellinger } 1416c66ac9dbSNicholas Bellinger 1417c66ac9dbSNicholas Bellinger int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *lu_gp, u16 lu_gp_id) 1418c66ac9dbSNicholas Bellinger { 1419c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp_tmp; 1420c66ac9dbSNicholas Bellinger u16 lu_gp_id_tmp; 1421c66ac9dbSNicholas Bellinger /* 1422c66ac9dbSNicholas Bellinger * The lu_gp->lu_gp_id may only be set once.. 1423c66ac9dbSNicholas Bellinger */ 1424c66ac9dbSNicholas Bellinger if (lu_gp->lu_gp_valid_id) { 14256708bb27SAndy Grover pr_warn("ALUA LU Group already has a valid ID," 1426c66ac9dbSNicholas Bellinger " ignoring request\n"); 1427e3d6f909SAndy Grover return -EINVAL; 1428c66ac9dbSNicholas Bellinger } 1429c66ac9dbSNicholas Bellinger 1430e3d6f909SAndy Grover spin_lock(&lu_gps_lock); 1431e3d6f909SAndy Grover if (alua_lu_gps_count == 0x0000ffff) { 14326708bb27SAndy Grover pr_err("Maximum ALUA alua_lu_gps_count:" 1433c66ac9dbSNicholas Bellinger " 0x0000ffff reached\n"); 1434e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1435c66ac9dbSNicholas Bellinger kmem_cache_free(t10_alua_lu_gp_cache, lu_gp); 1436e3d6f909SAndy Grover return -ENOSPC; 1437c66ac9dbSNicholas Bellinger } 1438c66ac9dbSNicholas Bellinger again: 1439c66ac9dbSNicholas Bellinger lu_gp_id_tmp = (lu_gp_id != 0) ? lu_gp_id : 1440e3d6f909SAndy Grover alua_lu_gps_counter++; 1441c66ac9dbSNicholas Bellinger 1442e3d6f909SAndy Grover list_for_each_entry(lu_gp_tmp, &lu_gps_list, lu_gp_node) { 1443c66ac9dbSNicholas Bellinger if (lu_gp_tmp->lu_gp_id == lu_gp_id_tmp) { 14446708bb27SAndy Grover if (!lu_gp_id) 1445c66ac9dbSNicholas Bellinger goto again; 1446c66ac9dbSNicholas Bellinger 14476708bb27SAndy Grover pr_warn("ALUA Logical Unit Group ID: %hu" 1448c66ac9dbSNicholas Bellinger " already exists, ignoring request\n", 1449c66ac9dbSNicholas Bellinger lu_gp_id); 1450e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1451e3d6f909SAndy Grover return -EINVAL; 1452c66ac9dbSNicholas Bellinger } 1453c66ac9dbSNicholas Bellinger } 1454c66ac9dbSNicholas Bellinger 1455c66ac9dbSNicholas Bellinger lu_gp->lu_gp_id = lu_gp_id_tmp; 1456c66ac9dbSNicholas Bellinger lu_gp->lu_gp_valid_id = 1; 1457e3d6f909SAndy Grover list_add_tail(&lu_gp->lu_gp_node, &lu_gps_list); 1458e3d6f909SAndy Grover alua_lu_gps_count++; 1459e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1460c66ac9dbSNicholas Bellinger 1461c66ac9dbSNicholas Bellinger return 0; 1462c66ac9dbSNicholas Bellinger } 1463c66ac9dbSNicholas Bellinger 1464c66ac9dbSNicholas Bellinger static struct t10_alua_lu_gp_member * 1465c66ac9dbSNicholas Bellinger core_alua_allocate_lu_gp_mem(struct se_device *dev) 1466c66ac9dbSNicholas Bellinger { 1467c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem; 1468c66ac9dbSNicholas Bellinger 1469c66ac9dbSNicholas Bellinger lu_gp_mem = kmem_cache_zalloc(t10_alua_lu_gp_mem_cache, GFP_KERNEL); 14706708bb27SAndy Grover if (!lu_gp_mem) { 14716708bb27SAndy Grover pr_err("Unable to allocate struct t10_alua_lu_gp_member\n"); 1472c66ac9dbSNicholas Bellinger return ERR_PTR(-ENOMEM); 1473c66ac9dbSNicholas Bellinger } 1474c66ac9dbSNicholas Bellinger INIT_LIST_HEAD(&lu_gp_mem->lu_gp_mem_list); 1475c66ac9dbSNicholas Bellinger spin_lock_init(&lu_gp_mem->lu_gp_mem_lock); 1476c66ac9dbSNicholas Bellinger atomic_set(&lu_gp_mem->lu_gp_mem_ref_cnt, 0); 1477c66ac9dbSNicholas Bellinger 1478c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp_mem_dev = dev; 1479c66ac9dbSNicholas Bellinger dev->dev_alua_lu_gp_mem = lu_gp_mem; 1480c66ac9dbSNicholas Bellinger 1481c66ac9dbSNicholas Bellinger return lu_gp_mem; 1482c66ac9dbSNicholas Bellinger } 1483c66ac9dbSNicholas Bellinger 1484c66ac9dbSNicholas Bellinger void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) 1485c66ac9dbSNicholas Bellinger { 1486c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem, *lu_gp_mem_tmp; 1487c66ac9dbSNicholas Bellinger /* 1488c66ac9dbSNicholas Bellinger * Once we have reached this point, config_item_put() has 1489c66ac9dbSNicholas Bellinger * already been called from target_core_alua_drop_lu_gp(). 1490c66ac9dbSNicholas Bellinger * 1491c66ac9dbSNicholas Bellinger * Here, we remove the *lu_gp from the global list so that 1492c66ac9dbSNicholas Bellinger * no associations can be made while we are releasing 1493c66ac9dbSNicholas Bellinger * struct t10_alua_lu_gp. 1494c66ac9dbSNicholas Bellinger */ 1495e3d6f909SAndy Grover spin_lock(&lu_gps_lock); 1496e3d6f909SAndy Grover list_del(&lu_gp->lu_gp_node); 1497e3d6f909SAndy Grover alua_lu_gps_count--; 1498e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1499c66ac9dbSNicholas Bellinger /* 1500c66ac9dbSNicholas Bellinger * Allow struct t10_alua_lu_gp * referenced by core_alua_get_lu_gp_by_name() 1501c66ac9dbSNicholas Bellinger * in target_core_configfs.c:target_core_store_alua_lu_gp() to be 1502c66ac9dbSNicholas Bellinger * released with core_alua_put_lu_gp_from_name() 1503c66ac9dbSNicholas Bellinger */ 1504c66ac9dbSNicholas Bellinger while (atomic_read(&lu_gp->lu_gp_ref_cnt)) 1505c66ac9dbSNicholas Bellinger cpu_relax(); 1506c66ac9dbSNicholas Bellinger /* 1507c66ac9dbSNicholas Bellinger * Release reference to struct t10_alua_lu_gp * from all associated 1508c66ac9dbSNicholas Bellinger * struct se_device. 1509c66ac9dbSNicholas Bellinger */ 1510c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 1511c66ac9dbSNicholas Bellinger list_for_each_entry_safe(lu_gp_mem, lu_gp_mem_tmp, 1512c66ac9dbSNicholas Bellinger &lu_gp->lu_gp_mem_list, lu_gp_mem_list) { 1513c66ac9dbSNicholas Bellinger if (lu_gp_mem->lu_gp_assoc) { 1514c66ac9dbSNicholas Bellinger list_del(&lu_gp_mem->lu_gp_mem_list); 1515c66ac9dbSNicholas Bellinger lu_gp->lu_gp_members--; 1516c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp_assoc = 0; 1517c66ac9dbSNicholas Bellinger } 1518c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1519c66ac9dbSNicholas Bellinger /* 1520c66ac9dbSNicholas Bellinger * 152125985edcSLucas De Marchi * lu_gp_mem is associated with a single 1522c66ac9dbSNicholas Bellinger * struct se_device->dev_alua_lu_gp_mem, and is released when 1523c66ac9dbSNicholas Bellinger * struct se_device is released via core_alua_free_lu_gp_mem(). 1524c66ac9dbSNicholas Bellinger * 1525c66ac9dbSNicholas Bellinger * If the passed lu_gp does NOT match the default_lu_gp, assume 1526f1ae05d5SHannes Reinecke * we want to re-associate a given lu_gp_mem with default_lu_gp. 1527c66ac9dbSNicholas Bellinger */ 1528c66ac9dbSNicholas Bellinger spin_lock(&lu_gp_mem->lu_gp_mem_lock); 1529e3d6f909SAndy Grover if (lu_gp != default_lu_gp) 1530c66ac9dbSNicholas Bellinger __core_alua_attach_lu_gp_mem(lu_gp_mem, 1531e3d6f909SAndy Grover default_lu_gp); 1532c66ac9dbSNicholas Bellinger else 1533c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp = NULL; 1534c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp_mem->lu_gp_mem_lock); 1535c66ac9dbSNicholas Bellinger 1536c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 1537c66ac9dbSNicholas Bellinger } 1538c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1539c66ac9dbSNicholas Bellinger 1540c66ac9dbSNicholas Bellinger kmem_cache_free(t10_alua_lu_gp_cache, lu_gp); 1541c66ac9dbSNicholas Bellinger } 1542c66ac9dbSNicholas Bellinger 1543c66ac9dbSNicholas Bellinger void core_alua_free_lu_gp_mem(struct se_device *dev) 1544c66ac9dbSNicholas Bellinger { 1545c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp; 1546c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem; 1547c66ac9dbSNicholas Bellinger 1548c66ac9dbSNicholas Bellinger lu_gp_mem = dev->dev_alua_lu_gp_mem; 15496708bb27SAndy Grover if (!lu_gp_mem) 1550c66ac9dbSNicholas Bellinger return; 1551c66ac9dbSNicholas Bellinger 1552c66ac9dbSNicholas Bellinger while (atomic_read(&lu_gp_mem->lu_gp_mem_ref_cnt)) 1553c66ac9dbSNicholas Bellinger cpu_relax(); 1554c66ac9dbSNicholas Bellinger 1555c66ac9dbSNicholas Bellinger spin_lock(&lu_gp_mem->lu_gp_mem_lock); 1556c66ac9dbSNicholas Bellinger lu_gp = lu_gp_mem->lu_gp; 15576708bb27SAndy Grover if (lu_gp) { 1558c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 1559c66ac9dbSNicholas Bellinger if (lu_gp_mem->lu_gp_assoc) { 1560c66ac9dbSNicholas Bellinger list_del(&lu_gp_mem->lu_gp_mem_list); 1561c66ac9dbSNicholas Bellinger lu_gp->lu_gp_members--; 1562c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp_assoc = 0; 1563c66ac9dbSNicholas Bellinger } 1564c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1565c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp = NULL; 1566c66ac9dbSNicholas Bellinger } 1567c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp_mem->lu_gp_mem_lock); 1568c66ac9dbSNicholas Bellinger 1569c66ac9dbSNicholas Bellinger kmem_cache_free(t10_alua_lu_gp_mem_cache, lu_gp_mem); 1570c66ac9dbSNicholas Bellinger } 1571c66ac9dbSNicholas Bellinger 1572c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *name) 1573c66ac9dbSNicholas Bellinger { 1574c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp; 1575c66ac9dbSNicholas Bellinger struct config_item *ci; 1576c66ac9dbSNicholas Bellinger 1577e3d6f909SAndy Grover spin_lock(&lu_gps_lock); 1578e3d6f909SAndy Grover list_for_each_entry(lu_gp, &lu_gps_list, lu_gp_node) { 15796708bb27SAndy Grover if (!lu_gp->lu_gp_valid_id) 1580c66ac9dbSNicholas Bellinger continue; 1581c66ac9dbSNicholas Bellinger ci = &lu_gp->lu_gp_group.cg_item; 15826708bb27SAndy Grover if (!strcmp(config_item_name(ci), name)) { 1583c66ac9dbSNicholas Bellinger atomic_inc(&lu_gp->lu_gp_ref_cnt); 1584e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1585c66ac9dbSNicholas Bellinger return lu_gp; 1586c66ac9dbSNicholas Bellinger } 1587c66ac9dbSNicholas Bellinger } 1588e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1589c66ac9dbSNicholas Bellinger 1590c66ac9dbSNicholas Bellinger return NULL; 1591c66ac9dbSNicholas Bellinger } 1592c66ac9dbSNicholas Bellinger 1593c66ac9dbSNicholas Bellinger void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *lu_gp) 1594c66ac9dbSNicholas Bellinger { 1595e3d6f909SAndy Grover spin_lock(&lu_gps_lock); 1596c66ac9dbSNicholas Bellinger atomic_dec(&lu_gp->lu_gp_ref_cnt); 1597e3d6f909SAndy Grover spin_unlock(&lu_gps_lock); 1598c66ac9dbSNicholas Bellinger } 1599c66ac9dbSNicholas Bellinger 1600c66ac9dbSNicholas Bellinger /* 1601c66ac9dbSNicholas Bellinger * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock 1602c66ac9dbSNicholas Bellinger */ 1603c66ac9dbSNicholas Bellinger void __core_alua_attach_lu_gp_mem( 1604c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem, 1605c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp) 1606c66ac9dbSNicholas Bellinger { 1607c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 1608c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp = lu_gp; 1609c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp_assoc = 1; 1610c66ac9dbSNicholas Bellinger list_add_tail(&lu_gp_mem->lu_gp_mem_list, &lu_gp->lu_gp_mem_list); 1611c66ac9dbSNicholas Bellinger lu_gp->lu_gp_members++; 1612c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1613c66ac9dbSNicholas Bellinger } 1614c66ac9dbSNicholas Bellinger 1615c66ac9dbSNicholas Bellinger /* 1616c66ac9dbSNicholas Bellinger * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock 1617c66ac9dbSNicholas Bellinger */ 1618c66ac9dbSNicholas Bellinger void __core_alua_drop_lu_gp_mem( 1619c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem, 1620c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *lu_gp) 1621c66ac9dbSNicholas Bellinger { 1622c66ac9dbSNicholas Bellinger spin_lock(&lu_gp->lu_gp_lock); 1623c66ac9dbSNicholas Bellinger list_del(&lu_gp_mem->lu_gp_mem_list); 1624c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp = NULL; 1625c66ac9dbSNicholas Bellinger lu_gp_mem->lu_gp_assoc = 0; 1626c66ac9dbSNicholas Bellinger lu_gp->lu_gp_members--; 1627c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp->lu_gp_lock); 1628c66ac9dbSNicholas Bellinger } 1629c66ac9dbSNicholas Bellinger 16300fd97ccfSChristoph Hellwig struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, 16310fd97ccfSChristoph Hellwig const char *name, int def_group) 1632c66ac9dbSNicholas Bellinger { 1633c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 1634c66ac9dbSNicholas Bellinger 1635c66ac9dbSNicholas Bellinger tg_pt_gp = kmem_cache_zalloc(t10_alua_tg_pt_gp_cache, GFP_KERNEL); 16366708bb27SAndy Grover if (!tg_pt_gp) { 16376708bb27SAndy Grover pr_err("Unable to allocate struct t10_alua_tg_pt_gp\n"); 1638c66ac9dbSNicholas Bellinger return NULL; 1639c66ac9dbSNicholas Bellinger } 1640c66ac9dbSNicholas Bellinger INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list); 1641adf653f9SChristoph Hellwig INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list); 1642d19c4643SMike Christie mutex_init(&tg_pt_gp->tg_pt_gp_transition_mutex); 1643c66ac9dbSNicholas Bellinger spin_lock_init(&tg_pt_gp->tg_pt_gp_lock); 1644c66ac9dbSNicholas Bellinger atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); 16450fd97ccfSChristoph Hellwig tg_pt_gp->tg_pt_gp_dev = dev; 1646d19c4643SMike Christie tg_pt_gp->tg_pt_gp_alua_access_state = 1647d19c4643SMike Christie ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED; 1648c66ac9dbSNicholas Bellinger /* 1649125d0119SHannes Reinecke * Enable both explicit and implicit ALUA support by default 1650c66ac9dbSNicholas Bellinger */ 1651c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_alua_access_type = 1652125d0119SHannes Reinecke TPGS_EXPLICIT_ALUA | TPGS_IMPLICIT_ALUA; 1653c66ac9dbSNicholas Bellinger /* 1654c66ac9dbSNicholas Bellinger * Set the default Active/NonOptimized Delay in milliseconds 1655c66ac9dbSNicholas Bellinger */ 1656c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS; 1657c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; 1658125d0119SHannes Reinecke tg_pt_gp->tg_pt_gp_implicit_trans_secs = ALUA_DEFAULT_IMPLICIT_TRANS_SECS; 1659c66ac9dbSNicholas Bellinger 1660c0dc941eSHannes Reinecke /* 1661c0dc941eSHannes Reinecke * Enable all supported states 1662c0dc941eSHannes Reinecke */ 1663c0dc941eSHannes Reinecke tg_pt_gp->tg_pt_gp_alua_supported_states = 1664c0dc941eSHannes Reinecke ALUA_T_SUP | ALUA_O_SUP | 1665c0dc941eSHannes Reinecke ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP; 1666c0dc941eSHannes Reinecke 1667c66ac9dbSNicholas Bellinger if (def_group) { 16680fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 1669c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_id = 16700fd97ccfSChristoph Hellwig dev->t10_alua.alua_tg_pt_gps_counter++; 1671c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_valid_id = 1; 16720fd97ccfSChristoph Hellwig dev->t10_alua.alua_tg_pt_gps_count++; 1673c66ac9dbSNicholas Bellinger list_add_tail(&tg_pt_gp->tg_pt_gp_list, 16740fd97ccfSChristoph Hellwig &dev->t10_alua.tg_pt_gps_list); 16750fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1676c66ac9dbSNicholas Bellinger } 1677c66ac9dbSNicholas Bellinger 1678c66ac9dbSNicholas Bellinger return tg_pt_gp; 1679c66ac9dbSNicholas Bellinger } 1680c66ac9dbSNicholas Bellinger 1681c66ac9dbSNicholas Bellinger int core_alua_set_tg_pt_gp_id( 1682c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 1683c66ac9dbSNicholas Bellinger u16 tg_pt_gp_id) 1684c66ac9dbSNicholas Bellinger { 16850fd97ccfSChristoph Hellwig struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; 1686c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp_tmp; 1687c66ac9dbSNicholas Bellinger u16 tg_pt_gp_id_tmp; 16880fd97ccfSChristoph Hellwig 1689c66ac9dbSNicholas Bellinger /* 1690c66ac9dbSNicholas Bellinger * The tg_pt_gp->tg_pt_gp_id may only be set once.. 1691c66ac9dbSNicholas Bellinger */ 1692c66ac9dbSNicholas Bellinger if (tg_pt_gp->tg_pt_gp_valid_id) { 16936708bb27SAndy Grover pr_warn("ALUA TG PT Group already has a valid ID," 1694c66ac9dbSNicholas Bellinger " ignoring request\n"); 1695e3d6f909SAndy Grover return -EINVAL; 1696c66ac9dbSNicholas Bellinger } 1697c66ac9dbSNicholas Bellinger 16980fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 16990fd97ccfSChristoph Hellwig if (dev->t10_alua.alua_tg_pt_gps_count == 0x0000ffff) { 17006708bb27SAndy Grover pr_err("Maximum ALUA alua_tg_pt_gps_count:" 1701c66ac9dbSNicholas Bellinger " 0x0000ffff reached\n"); 17020fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1703c66ac9dbSNicholas Bellinger kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); 1704e3d6f909SAndy Grover return -ENOSPC; 1705c66ac9dbSNicholas Bellinger } 1706c66ac9dbSNicholas Bellinger again: 1707c66ac9dbSNicholas Bellinger tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id : 17080fd97ccfSChristoph Hellwig dev->t10_alua.alua_tg_pt_gps_counter++; 1709c66ac9dbSNicholas Bellinger 17100fd97ccfSChristoph Hellwig list_for_each_entry(tg_pt_gp_tmp, &dev->t10_alua.tg_pt_gps_list, 1711c66ac9dbSNicholas Bellinger tg_pt_gp_list) { 1712c66ac9dbSNicholas Bellinger if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) { 17136708bb27SAndy Grover if (!tg_pt_gp_id) 1714c66ac9dbSNicholas Bellinger goto again; 1715c66ac9dbSNicholas Bellinger 17166708bb27SAndy Grover pr_err("ALUA Target Port Group ID: %hu already" 1717c66ac9dbSNicholas Bellinger " exists, ignoring request\n", tg_pt_gp_id); 17180fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1719e3d6f909SAndy Grover return -EINVAL; 1720c66ac9dbSNicholas Bellinger } 1721c66ac9dbSNicholas Bellinger } 1722c66ac9dbSNicholas Bellinger 1723c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp; 1724c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_valid_id = 1; 1725c66ac9dbSNicholas Bellinger list_add_tail(&tg_pt_gp->tg_pt_gp_list, 17260fd97ccfSChristoph Hellwig &dev->t10_alua.tg_pt_gps_list); 17270fd97ccfSChristoph Hellwig dev->t10_alua.alua_tg_pt_gps_count++; 17280fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1729c66ac9dbSNicholas Bellinger 1730c66ac9dbSNicholas Bellinger return 0; 1731c66ac9dbSNicholas Bellinger } 1732c66ac9dbSNicholas Bellinger 1733c66ac9dbSNicholas Bellinger void core_alua_free_tg_pt_gp( 1734c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp) 1735c66ac9dbSNicholas Bellinger { 17360fd97ccfSChristoph Hellwig struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; 1737adf653f9SChristoph Hellwig struct se_lun *lun, *next; 17380fd97ccfSChristoph Hellwig 1739c66ac9dbSNicholas Bellinger /* 1740c66ac9dbSNicholas Bellinger * Once we have reached this point, config_item_put() has already 1741c66ac9dbSNicholas Bellinger * been called from target_core_alua_drop_tg_pt_gp(). 1742c66ac9dbSNicholas Bellinger * 1743c66ac9dbSNicholas Bellinger * Here we remove *tg_pt_gp from the global list so that 1744f1ae05d5SHannes Reinecke * no associations *OR* explicit ALUA via SET_TARGET_PORT_GROUPS 1745c66ac9dbSNicholas Bellinger * can be made while we are releasing struct t10_alua_tg_pt_gp. 1746c66ac9dbSNicholas Bellinger */ 17470fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 174882129697Stangwenji if (tg_pt_gp->tg_pt_gp_valid_id) { 1749c66ac9dbSNicholas Bellinger list_del(&tg_pt_gp->tg_pt_gp_list); 175082129697Stangwenji dev->t10_alua.alua_tg_pt_gps_count--; 175182129697Stangwenji } 17520fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 17530fd97ccfSChristoph Hellwig 1754c66ac9dbSNicholas Bellinger /* 1755c66ac9dbSNicholas Bellinger * Allow a struct t10_alua_tg_pt_gp_member * referenced by 1756c66ac9dbSNicholas Bellinger * core_alua_get_tg_pt_gp_by_name() in 1757c66ac9dbSNicholas Bellinger * target_core_configfs.c:target_core_store_alua_tg_pt_gp() 1758c66ac9dbSNicholas Bellinger * to be released with core_alua_put_tg_pt_gp_from_name(). 1759c66ac9dbSNicholas Bellinger */ 1760c66ac9dbSNicholas Bellinger while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt)) 1761c66ac9dbSNicholas Bellinger cpu_relax(); 17620fd97ccfSChristoph Hellwig 1763c66ac9dbSNicholas Bellinger /* 1764c66ac9dbSNicholas Bellinger * Release reference to struct t10_alua_tg_pt_gp from all associated 1765c66ac9dbSNicholas Bellinger * struct se_port. 1766c66ac9dbSNicholas Bellinger */ 1767c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 1768adf653f9SChristoph Hellwig list_for_each_entry_safe(lun, next, 1769adf653f9SChristoph Hellwig &tg_pt_gp->tg_pt_gp_lun_list, lun_tg_pt_gp_link) { 1770adf653f9SChristoph Hellwig list_del_init(&lun->lun_tg_pt_gp_link); 1771c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_members--; 1772adf653f9SChristoph Hellwig 1773c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 1774c66ac9dbSNicholas Bellinger /* 1775c66ac9dbSNicholas Bellinger * If the passed tg_pt_gp does NOT match the default_tg_pt_gp, 1776f1ae05d5SHannes Reinecke * assume we want to re-associate a given tg_pt_gp_mem with 1777c66ac9dbSNicholas Bellinger * default_tg_pt_gp. 1778c66ac9dbSNicholas Bellinger */ 1779adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 17800fd97ccfSChristoph Hellwig if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) { 1781adf653f9SChristoph Hellwig __target_attach_tg_pt_gp(lun, 17820fd97ccfSChristoph Hellwig dev->t10_alua.default_tg_pt_gp); 1783c66ac9dbSNicholas Bellinger } else 1784adf653f9SChristoph Hellwig lun->lun_tg_pt_gp = NULL; 1785adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 1786c66ac9dbSNicholas Bellinger 1787c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 1788c66ac9dbSNicholas Bellinger } 1789c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 1790c66ac9dbSNicholas Bellinger 1791c66ac9dbSNicholas Bellinger kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); 1792c66ac9dbSNicholas Bellinger } 1793c66ac9dbSNicholas Bellinger 1794c66ac9dbSNicholas Bellinger static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( 17950fd97ccfSChristoph Hellwig struct se_device *dev, const char *name) 1796c66ac9dbSNicholas Bellinger { 1797c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 1798c66ac9dbSNicholas Bellinger struct config_item *ci; 1799c66ac9dbSNicholas Bellinger 18000fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 18010fd97ccfSChristoph Hellwig list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, 1802c66ac9dbSNicholas Bellinger tg_pt_gp_list) { 18036708bb27SAndy Grover if (!tg_pt_gp->tg_pt_gp_valid_id) 1804c66ac9dbSNicholas Bellinger continue; 1805c66ac9dbSNicholas Bellinger ci = &tg_pt_gp->tg_pt_gp_group.cg_item; 18066708bb27SAndy Grover if (!strcmp(config_item_name(ci), name)) { 1807c66ac9dbSNicholas Bellinger atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); 18080fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1809c66ac9dbSNicholas Bellinger return tg_pt_gp; 1810c66ac9dbSNicholas Bellinger } 1811c66ac9dbSNicholas Bellinger } 18120fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1813c66ac9dbSNicholas Bellinger 1814c66ac9dbSNicholas Bellinger return NULL; 1815c66ac9dbSNicholas Bellinger } 1816c66ac9dbSNicholas Bellinger 1817c66ac9dbSNicholas Bellinger static void core_alua_put_tg_pt_gp_from_name( 1818c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp) 1819c66ac9dbSNicholas Bellinger { 18200fd97ccfSChristoph Hellwig struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; 1821c66ac9dbSNicholas Bellinger 18220fd97ccfSChristoph Hellwig spin_lock(&dev->t10_alua.tg_pt_gps_lock); 1823c66ac9dbSNicholas Bellinger atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); 18240fd97ccfSChristoph Hellwig spin_unlock(&dev->t10_alua.tg_pt_gps_lock); 1825c66ac9dbSNicholas Bellinger } 1826c66ac9dbSNicholas Bellinger 1827adf653f9SChristoph Hellwig static void __target_attach_tg_pt_gp(struct se_lun *lun, 1828c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp) 1829c66ac9dbSNicholas Bellinger { 18303dd348fcSHannes Reinecke struct se_dev_entry *se_deve; 18313dd348fcSHannes Reinecke 1832adf653f9SChristoph Hellwig assert_spin_locked(&lun->lun_tg_pt_gp_lock); 1833adf653f9SChristoph Hellwig 1834c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 1835adf653f9SChristoph Hellwig lun->lun_tg_pt_gp = tg_pt_gp; 1836adf653f9SChristoph Hellwig list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list); 1837c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_members++; 18383dd348fcSHannes Reinecke spin_lock(&lun->lun_deve_lock); 18393dd348fcSHannes Reinecke list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) 18403dd348fcSHannes Reinecke core_scsi3_ua_allocate(se_deve, 0x3f, 18413dd348fcSHannes Reinecke ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED); 18423dd348fcSHannes Reinecke spin_unlock(&lun->lun_deve_lock); 1843c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 1844c66ac9dbSNicholas Bellinger } 1845c66ac9dbSNicholas Bellinger 1846adf653f9SChristoph Hellwig void target_attach_tg_pt_gp(struct se_lun *lun, 1847c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp) 1848c66ac9dbSNicholas Bellinger { 1849adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 1850adf653f9SChristoph Hellwig __target_attach_tg_pt_gp(lun, tg_pt_gp); 1851adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 1852c66ac9dbSNicholas Bellinger } 1853c66ac9dbSNicholas Bellinger 1854adf653f9SChristoph Hellwig static void __target_detach_tg_pt_gp(struct se_lun *lun, 1855adf653f9SChristoph Hellwig struct t10_alua_tg_pt_gp *tg_pt_gp) 1856adf653f9SChristoph Hellwig { 1857adf653f9SChristoph Hellwig assert_spin_locked(&lun->lun_tg_pt_gp_lock); 1858adf653f9SChristoph Hellwig 1859c66ac9dbSNicholas Bellinger spin_lock(&tg_pt_gp->tg_pt_gp_lock); 1860adf653f9SChristoph Hellwig list_del_init(&lun->lun_tg_pt_gp_link); 1861c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_members--; 1862c66ac9dbSNicholas Bellinger spin_unlock(&tg_pt_gp->tg_pt_gp_lock); 1863adf653f9SChristoph Hellwig 1864adf653f9SChristoph Hellwig lun->lun_tg_pt_gp = NULL; 1865c66ac9dbSNicholas Bellinger } 1866c66ac9dbSNicholas Bellinger 1867adf653f9SChristoph Hellwig void target_detach_tg_pt_gp(struct se_lun *lun) 1868adf653f9SChristoph Hellwig { 1869adf653f9SChristoph Hellwig struct t10_alua_tg_pt_gp *tg_pt_gp; 1870adf653f9SChristoph Hellwig 1871adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 1872adf653f9SChristoph Hellwig tg_pt_gp = lun->lun_tg_pt_gp; 1873adf653f9SChristoph Hellwig if (tg_pt_gp) 1874adf653f9SChristoph Hellwig __target_detach_tg_pt_gp(lun, tg_pt_gp); 1875adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 1876adf653f9SChristoph Hellwig } 1877adf653f9SChristoph Hellwig 1878adf653f9SChristoph Hellwig ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page) 1879c66ac9dbSNicholas Bellinger { 1880c66ac9dbSNicholas Bellinger struct config_item *tg_pt_ci; 1881c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp; 1882c66ac9dbSNicholas Bellinger ssize_t len = 0; 1883c66ac9dbSNicholas Bellinger 1884adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 1885adf653f9SChristoph Hellwig tg_pt_gp = lun->lun_tg_pt_gp; 18866708bb27SAndy Grover if (tg_pt_gp) { 1887c66ac9dbSNicholas Bellinger tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item; 1888c66ac9dbSNicholas Bellinger len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:" 1889c66ac9dbSNicholas Bellinger " %hu\nTG Port Primary Access State: %s\nTG Port " 1890c66ac9dbSNicholas Bellinger "Primary Access Status: %s\nTG Port Secondary Access" 1891c66ac9dbSNicholas Bellinger " State: %s\nTG Port Secondary Access Status: %s\n", 1892c66ac9dbSNicholas Bellinger config_item_name(tg_pt_ci), tg_pt_gp->tg_pt_gp_id, 1893d19c4643SMike Christie core_alua_dump_state( 1894d19c4643SMike Christie tg_pt_gp->tg_pt_gp_alua_access_state), 1895c66ac9dbSNicholas Bellinger core_alua_dump_status( 1896c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_alua_access_status), 1897adf653f9SChristoph Hellwig atomic_read(&lun->lun_tg_pt_secondary_offline) ? 1898c66ac9dbSNicholas Bellinger "Offline" : "None", 1899adf653f9SChristoph Hellwig core_alua_dump_status(lun->lun_tg_pt_secondary_stat)); 1900c66ac9dbSNicholas Bellinger } 1901adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 1902c66ac9dbSNicholas Bellinger 1903c66ac9dbSNicholas Bellinger return len; 1904c66ac9dbSNicholas Bellinger } 1905c66ac9dbSNicholas Bellinger 1906c66ac9dbSNicholas Bellinger ssize_t core_alua_store_tg_pt_gp_info( 1907adf653f9SChristoph Hellwig struct se_lun *lun, 1908c66ac9dbSNicholas Bellinger const char *page, 1909c66ac9dbSNicholas Bellinger size_t count) 1910c66ac9dbSNicholas Bellinger { 1911adf653f9SChristoph Hellwig struct se_portal_group *tpg = lun->lun_tpg; 19124cc987eaSNicholas Bellinger /* 19134cc987eaSNicholas Bellinger * rcu_dereference_raw protected by se_lun->lun_group symlink 19144cc987eaSNicholas Bellinger * reference to se_device->dev_group. 19154cc987eaSNicholas Bellinger */ 19164cc987eaSNicholas Bellinger struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); 1917c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; 1918c66ac9dbSNicholas Bellinger unsigned char buf[TG_PT_GROUP_NAME_BUF]; 1919c66ac9dbSNicholas Bellinger int move = 0; 1920c66ac9dbSNicholas Bellinger 192169088a04SBodo Stroesser if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA || 1922adf653f9SChristoph Hellwig (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) 1923adf653f9SChristoph Hellwig return -ENODEV; 1924c66ac9dbSNicholas Bellinger 1925c66ac9dbSNicholas Bellinger if (count > TG_PT_GROUP_NAME_BUF) { 19266708bb27SAndy Grover pr_err("ALUA Target Port Group alias too large!\n"); 1927c66ac9dbSNicholas Bellinger return -EINVAL; 1928c66ac9dbSNicholas Bellinger } 1929c66ac9dbSNicholas Bellinger memset(buf, 0, TG_PT_GROUP_NAME_BUF); 1930c66ac9dbSNicholas Bellinger memcpy(buf, page, count); 1931c66ac9dbSNicholas Bellinger /* 1932c66ac9dbSNicholas Bellinger * Any ALUA target port group alias besides "NULL" means we will be 1933c66ac9dbSNicholas Bellinger * making a new group association. 1934c66ac9dbSNicholas Bellinger */ 1935c66ac9dbSNicholas Bellinger if (strcmp(strstrip(buf), "NULL")) { 1936c66ac9dbSNicholas Bellinger /* 1937c66ac9dbSNicholas Bellinger * core_alua_get_tg_pt_gp_by_name() will increment reference to 1938c66ac9dbSNicholas Bellinger * struct t10_alua_tg_pt_gp. This reference is released with 1939c66ac9dbSNicholas Bellinger * core_alua_put_tg_pt_gp_from_name() below. 1940c66ac9dbSNicholas Bellinger */ 19410fd97ccfSChristoph Hellwig tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(dev, 1942c66ac9dbSNicholas Bellinger strstrip(buf)); 19436708bb27SAndy Grover if (!tg_pt_gp_new) 1944c66ac9dbSNicholas Bellinger return -ENODEV; 1945c66ac9dbSNicholas Bellinger } 1946c66ac9dbSNicholas Bellinger 1947adf653f9SChristoph Hellwig spin_lock(&lun->lun_tg_pt_gp_lock); 1948adf653f9SChristoph Hellwig tg_pt_gp = lun->lun_tg_pt_gp; 19496708bb27SAndy Grover if (tg_pt_gp) { 1950c66ac9dbSNicholas Bellinger /* 1951c66ac9dbSNicholas Bellinger * Clearing an existing tg_pt_gp association, and replacing 1952c66ac9dbSNicholas Bellinger * with the default_tg_pt_gp. 1953c66ac9dbSNicholas Bellinger */ 19546708bb27SAndy Grover if (!tg_pt_gp_new) { 19556708bb27SAndy Grover pr_debug("Target_Core_ConfigFS: Moving" 1956c66ac9dbSNicholas Bellinger " %s/tpgt_%hu/%s from ALUA Target Port Group:" 1957c66ac9dbSNicholas Bellinger " alua/%s, ID: %hu back to" 1958c66ac9dbSNicholas Bellinger " default_tg_pt_gp\n", 1959e3d6f909SAndy Grover tpg->se_tpg_tfo->tpg_get_wwn(tpg), 1960e3d6f909SAndy Grover tpg->se_tpg_tfo->tpg_get_tag(tpg), 1961c66ac9dbSNicholas Bellinger config_item_name(&lun->lun_group.cg_item), 1962c66ac9dbSNicholas Bellinger config_item_name( 1963c66ac9dbSNicholas Bellinger &tg_pt_gp->tg_pt_gp_group.cg_item), 1964c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_id); 1965c66ac9dbSNicholas Bellinger 1966adf653f9SChristoph Hellwig __target_detach_tg_pt_gp(lun, tg_pt_gp); 1967adf653f9SChristoph Hellwig __target_attach_tg_pt_gp(lun, 19680fd97ccfSChristoph Hellwig dev->t10_alua.default_tg_pt_gp); 1969adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 1970c66ac9dbSNicholas Bellinger 1971c66ac9dbSNicholas Bellinger return count; 1972c66ac9dbSNicholas Bellinger } 1973adf653f9SChristoph Hellwig __target_detach_tg_pt_gp(lun, tg_pt_gp); 1974c66ac9dbSNicholas Bellinger move = 1; 1975c66ac9dbSNicholas Bellinger } 1976adf653f9SChristoph Hellwig 1977adf653f9SChristoph Hellwig __target_attach_tg_pt_gp(lun, tg_pt_gp_new); 1978adf653f9SChristoph Hellwig spin_unlock(&lun->lun_tg_pt_gp_lock); 19796708bb27SAndy Grover pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA" 1980c66ac9dbSNicholas Bellinger " Target Port Group: alua/%s, ID: %hu\n", (move) ? 1981e3d6f909SAndy Grover "Moving" : "Adding", tpg->se_tpg_tfo->tpg_get_wwn(tpg), 1982e3d6f909SAndy Grover tpg->se_tpg_tfo->tpg_get_tag(tpg), 1983c66ac9dbSNicholas Bellinger config_item_name(&lun->lun_group.cg_item), 1984c66ac9dbSNicholas Bellinger config_item_name(&tg_pt_gp_new->tg_pt_gp_group.cg_item), 1985c66ac9dbSNicholas Bellinger tg_pt_gp_new->tg_pt_gp_id); 1986c66ac9dbSNicholas Bellinger 1987c66ac9dbSNicholas Bellinger core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new); 1988c66ac9dbSNicholas Bellinger return count; 1989c66ac9dbSNicholas Bellinger } 1990c66ac9dbSNicholas Bellinger 1991c66ac9dbSNicholas Bellinger ssize_t core_alua_show_access_type( 1992c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 1993c66ac9dbSNicholas Bellinger char *page) 1994c66ac9dbSNicholas Bellinger { 1995125d0119SHannes Reinecke if ((tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA) && 1996125d0119SHannes Reinecke (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICIT_ALUA)) 1997125d0119SHannes Reinecke return sprintf(page, "Implicit and Explicit\n"); 1998125d0119SHannes Reinecke else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICIT_ALUA) 1999125d0119SHannes Reinecke return sprintf(page, "Implicit\n"); 2000125d0119SHannes Reinecke else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA) 2001125d0119SHannes Reinecke return sprintf(page, "Explicit\n"); 2002c66ac9dbSNicholas Bellinger else 2003c66ac9dbSNicholas Bellinger return sprintf(page, "None\n"); 2004c66ac9dbSNicholas Bellinger } 2005c66ac9dbSNicholas Bellinger 2006c66ac9dbSNicholas Bellinger ssize_t core_alua_store_access_type( 2007c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2008c66ac9dbSNicholas Bellinger const char *page, 2009c66ac9dbSNicholas Bellinger size_t count) 2010c66ac9dbSNicholas Bellinger { 2011c66ac9dbSNicholas Bellinger unsigned long tmp; 2012c66ac9dbSNicholas Bellinger int ret; 2013c66ac9dbSNicholas Bellinger 201457103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2015c66ac9dbSNicholas Bellinger if (ret < 0) { 20166708bb27SAndy Grover pr_err("Unable to extract alua_access_type\n"); 201757103d7fSJingoo Han return ret; 2018c66ac9dbSNicholas Bellinger } 2019c66ac9dbSNicholas Bellinger if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) { 20206708bb27SAndy Grover pr_err("Illegal value for alua_access_type:" 2021c66ac9dbSNicholas Bellinger " %lu\n", tmp); 2022c66ac9dbSNicholas Bellinger return -EINVAL; 2023c66ac9dbSNicholas Bellinger } 2024c66ac9dbSNicholas Bellinger if (tmp == 3) 2025c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_alua_access_type = 2026125d0119SHannes Reinecke TPGS_IMPLICIT_ALUA | TPGS_EXPLICIT_ALUA; 2027c66ac9dbSNicholas Bellinger else if (tmp == 2) 2028125d0119SHannes Reinecke tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_EXPLICIT_ALUA; 2029c66ac9dbSNicholas Bellinger else if (tmp == 1) 2030125d0119SHannes Reinecke tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_IMPLICIT_ALUA; 2031c66ac9dbSNicholas Bellinger else 2032c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_alua_access_type = 0; 2033c66ac9dbSNicholas Bellinger 2034c66ac9dbSNicholas Bellinger return count; 2035c66ac9dbSNicholas Bellinger } 2036c66ac9dbSNicholas Bellinger 2037c66ac9dbSNicholas Bellinger ssize_t core_alua_show_nonop_delay_msecs( 2038c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2039c66ac9dbSNicholas Bellinger char *page) 2040c66ac9dbSNicholas Bellinger { 2041c66ac9dbSNicholas Bellinger return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_nonop_delay_msecs); 2042c66ac9dbSNicholas Bellinger } 2043c66ac9dbSNicholas Bellinger 2044c66ac9dbSNicholas Bellinger ssize_t core_alua_store_nonop_delay_msecs( 2045c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2046c66ac9dbSNicholas Bellinger const char *page, 2047c66ac9dbSNicholas Bellinger size_t count) 2048c66ac9dbSNicholas Bellinger { 2049c66ac9dbSNicholas Bellinger unsigned long tmp; 2050c66ac9dbSNicholas Bellinger int ret; 2051c66ac9dbSNicholas Bellinger 205257103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2053c66ac9dbSNicholas Bellinger if (ret < 0) { 20546708bb27SAndy Grover pr_err("Unable to extract nonop_delay_msecs\n"); 205557103d7fSJingoo Han return ret; 2056c66ac9dbSNicholas Bellinger } 2057c66ac9dbSNicholas Bellinger if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) { 20586708bb27SAndy Grover pr_err("Passed nonop_delay_msecs: %lu, exceeds" 2059c66ac9dbSNicholas Bellinger " ALUA_MAX_NONOP_DELAY_MSECS: %d\n", tmp, 2060c66ac9dbSNicholas Bellinger ALUA_MAX_NONOP_DELAY_MSECS); 2061c66ac9dbSNicholas Bellinger return -EINVAL; 2062c66ac9dbSNicholas Bellinger } 2063c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_nonop_delay_msecs = (int)tmp; 2064c66ac9dbSNicholas Bellinger 2065c66ac9dbSNicholas Bellinger return count; 2066c66ac9dbSNicholas Bellinger } 2067c66ac9dbSNicholas Bellinger 2068c66ac9dbSNicholas Bellinger ssize_t core_alua_show_trans_delay_msecs( 2069c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2070c66ac9dbSNicholas Bellinger char *page) 2071c66ac9dbSNicholas Bellinger { 2072c66ac9dbSNicholas Bellinger return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_trans_delay_msecs); 2073c66ac9dbSNicholas Bellinger } 2074c66ac9dbSNicholas Bellinger 2075c66ac9dbSNicholas Bellinger ssize_t core_alua_store_trans_delay_msecs( 2076c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2077c66ac9dbSNicholas Bellinger const char *page, 2078c66ac9dbSNicholas Bellinger size_t count) 2079c66ac9dbSNicholas Bellinger { 2080c66ac9dbSNicholas Bellinger unsigned long tmp; 2081c66ac9dbSNicholas Bellinger int ret; 2082c66ac9dbSNicholas Bellinger 208357103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2084c66ac9dbSNicholas Bellinger if (ret < 0) { 20856708bb27SAndy Grover pr_err("Unable to extract trans_delay_msecs\n"); 208657103d7fSJingoo Han return ret; 2087c66ac9dbSNicholas Bellinger } 2088c66ac9dbSNicholas Bellinger if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) { 20896708bb27SAndy Grover pr_err("Passed trans_delay_msecs: %lu, exceeds" 2090c66ac9dbSNicholas Bellinger " ALUA_MAX_TRANS_DELAY_MSECS: %d\n", tmp, 2091c66ac9dbSNicholas Bellinger ALUA_MAX_TRANS_DELAY_MSECS); 2092c66ac9dbSNicholas Bellinger return -EINVAL; 2093c66ac9dbSNicholas Bellinger } 2094c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_trans_delay_msecs = (int)tmp; 2095c66ac9dbSNicholas Bellinger 2096c66ac9dbSNicholas Bellinger return count; 2097c66ac9dbSNicholas Bellinger } 2098c66ac9dbSNicholas Bellinger 2099125d0119SHannes Reinecke ssize_t core_alua_show_implicit_trans_secs( 21005b9a4d72SNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 21015b9a4d72SNicholas Bellinger char *page) 21025b9a4d72SNicholas Bellinger { 2103125d0119SHannes Reinecke return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_implicit_trans_secs); 21045b9a4d72SNicholas Bellinger } 21055b9a4d72SNicholas Bellinger 2106125d0119SHannes Reinecke ssize_t core_alua_store_implicit_trans_secs( 21075b9a4d72SNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 21085b9a4d72SNicholas Bellinger const char *page, 21095b9a4d72SNicholas Bellinger size_t count) 21105b9a4d72SNicholas Bellinger { 21115b9a4d72SNicholas Bellinger unsigned long tmp; 21125b9a4d72SNicholas Bellinger int ret; 21135b9a4d72SNicholas Bellinger 211457103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 21155b9a4d72SNicholas Bellinger if (ret < 0) { 2116125d0119SHannes Reinecke pr_err("Unable to extract implicit_trans_secs\n"); 211757103d7fSJingoo Han return ret; 21185b9a4d72SNicholas Bellinger } 2119125d0119SHannes Reinecke if (tmp > ALUA_MAX_IMPLICIT_TRANS_SECS) { 2120125d0119SHannes Reinecke pr_err("Passed implicit_trans_secs: %lu, exceeds" 2121125d0119SHannes Reinecke " ALUA_MAX_IMPLICIT_TRANS_SECS: %d\n", tmp, 2122125d0119SHannes Reinecke ALUA_MAX_IMPLICIT_TRANS_SECS); 21235b9a4d72SNicholas Bellinger return -EINVAL; 21245b9a4d72SNicholas Bellinger } 2125125d0119SHannes Reinecke tg_pt_gp->tg_pt_gp_implicit_trans_secs = (int)tmp; 21265b9a4d72SNicholas Bellinger 21275b9a4d72SNicholas Bellinger return count; 21285b9a4d72SNicholas Bellinger } 21295b9a4d72SNicholas Bellinger 2130c66ac9dbSNicholas Bellinger ssize_t core_alua_show_preferred_bit( 2131c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2132c66ac9dbSNicholas Bellinger char *page) 2133c66ac9dbSNicholas Bellinger { 2134c66ac9dbSNicholas Bellinger return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_pref); 2135c66ac9dbSNicholas Bellinger } 2136c66ac9dbSNicholas Bellinger 2137c66ac9dbSNicholas Bellinger ssize_t core_alua_store_preferred_bit( 2138c66ac9dbSNicholas Bellinger struct t10_alua_tg_pt_gp *tg_pt_gp, 2139c66ac9dbSNicholas Bellinger const char *page, 2140c66ac9dbSNicholas Bellinger size_t count) 2141c66ac9dbSNicholas Bellinger { 2142c66ac9dbSNicholas Bellinger unsigned long tmp; 2143c66ac9dbSNicholas Bellinger int ret; 2144c66ac9dbSNicholas Bellinger 214557103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2146c66ac9dbSNicholas Bellinger if (ret < 0) { 21476708bb27SAndy Grover pr_err("Unable to extract preferred ALUA value\n"); 214857103d7fSJingoo Han return ret; 2149c66ac9dbSNicholas Bellinger } 2150c66ac9dbSNicholas Bellinger if ((tmp != 0) && (tmp != 1)) { 21516708bb27SAndy Grover pr_err("Illegal value for preferred ALUA: %lu\n", tmp); 2152c66ac9dbSNicholas Bellinger return -EINVAL; 2153c66ac9dbSNicholas Bellinger } 2154c66ac9dbSNicholas Bellinger tg_pt_gp->tg_pt_gp_pref = (int)tmp; 2155c66ac9dbSNicholas Bellinger 2156c66ac9dbSNicholas Bellinger return count; 2157c66ac9dbSNicholas Bellinger } 2158c66ac9dbSNicholas Bellinger 2159c66ac9dbSNicholas Bellinger ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page) 2160c66ac9dbSNicholas Bellinger { 2161c66ac9dbSNicholas Bellinger return sprintf(page, "%d\n", 2162adf653f9SChristoph Hellwig atomic_read(&lun->lun_tg_pt_secondary_offline)); 2163c66ac9dbSNicholas Bellinger } 2164c66ac9dbSNicholas Bellinger 2165c66ac9dbSNicholas Bellinger ssize_t core_alua_store_offline_bit( 2166c66ac9dbSNicholas Bellinger struct se_lun *lun, 2167c66ac9dbSNicholas Bellinger const char *page, 2168c66ac9dbSNicholas Bellinger size_t count) 2169c66ac9dbSNicholas Bellinger { 21704cc987eaSNicholas Bellinger /* 21714cc987eaSNicholas Bellinger * rcu_dereference_raw protected by se_lun->lun_group symlink 21724cc987eaSNicholas Bellinger * reference to se_device->dev_group. 21734cc987eaSNicholas Bellinger */ 21744cc987eaSNicholas Bellinger struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); 2175c66ac9dbSNicholas Bellinger unsigned long tmp; 2176c66ac9dbSNicholas Bellinger int ret; 2177c66ac9dbSNicholas Bellinger 217869088a04SBodo Stroesser if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA || 2179adf653f9SChristoph Hellwig (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) 2180c66ac9dbSNicholas Bellinger return -ENODEV; 2181c66ac9dbSNicholas Bellinger 218257103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2183c66ac9dbSNicholas Bellinger if (ret < 0) { 21846708bb27SAndy Grover pr_err("Unable to extract alua_tg_pt_offline value\n"); 218557103d7fSJingoo Han return ret; 2186c66ac9dbSNicholas Bellinger } 2187c66ac9dbSNicholas Bellinger if ((tmp != 0) && (tmp != 1)) { 21886708bb27SAndy Grover pr_err("Illegal value for alua_tg_pt_offline: %lu\n", 2189c66ac9dbSNicholas Bellinger tmp); 2190c66ac9dbSNicholas Bellinger return -EINVAL; 2191c66ac9dbSNicholas Bellinger } 2192c66ac9dbSNicholas Bellinger 2193adf653f9SChristoph Hellwig ret = core_alua_set_tg_pt_secondary_state(lun, 0, (int)tmp); 2194c66ac9dbSNicholas Bellinger if (ret < 0) 2195c66ac9dbSNicholas Bellinger return -EINVAL; 2196c66ac9dbSNicholas Bellinger 2197c66ac9dbSNicholas Bellinger return count; 2198c66ac9dbSNicholas Bellinger } 2199c66ac9dbSNicholas Bellinger 2200c66ac9dbSNicholas Bellinger ssize_t core_alua_show_secondary_status( 2201c66ac9dbSNicholas Bellinger struct se_lun *lun, 2202c66ac9dbSNicholas Bellinger char *page) 2203c66ac9dbSNicholas Bellinger { 2204adf653f9SChristoph Hellwig return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_stat); 2205c66ac9dbSNicholas Bellinger } 2206c66ac9dbSNicholas Bellinger 2207c66ac9dbSNicholas Bellinger ssize_t core_alua_store_secondary_status( 2208c66ac9dbSNicholas Bellinger struct se_lun *lun, 2209c66ac9dbSNicholas Bellinger const char *page, 2210c66ac9dbSNicholas Bellinger size_t count) 2211c66ac9dbSNicholas Bellinger { 2212c66ac9dbSNicholas Bellinger unsigned long tmp; 2213c66ac9dbSNicholas Bellinger int ret; 2214c66ac9dbSNicholas Bellinger 221557103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2216c66ac9dbSNicholas Bellinger if (ret < 0) { 22176708bb27SAndy Grover pr_err("Unable to extract alua_tg_pt_status\n"); 221857103d7fSJingoo Han return ret; 2219c66ac9dbSNicholas Bellinger } 2220c66ac9dbSNicholas Bellinger if ((tmp != ALUA_STATUS_NONE) && 2221125d0119SHannes Reinecke (tmp != ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && 2222125d0119SHannes Reinecke (tmp != ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA)) { 22236708bb27SAndy Grover pr_err("Illegal value for alua_tg_pt_status: %lu\n", 2224c66ac9dbSNicholas Bellinger tmp); 2225c66ac9dbSNicholas Bellinger return -EINVAL; 2226c66ac9dbSNicholas Bellinger } 2227adf653f9SChristoph Hellwig lun->lun_tg_pt_secondary_stat = (int)tmp; 2228c66ac9dbSNicholas Bellinger 2229c66ac9dbSNicholas Bellinger return count; 2230c66ac9dbSNicholas Bellinger } 2231c66ac9dbSNicholas Bellinger 2232c66ac9dbSNicholas Bellinger ssize_t core_alua_show_secondary_write_metadata( 2233c66ac9dbSNicholas Bellinger struct se_lun *lun, 2234c66ac9dbSNicholas Bellinger char *page) 2235c66ac9dbSNicholas Bellinger { 2236adf653f9SChristoph Hellwig return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_write_md); 2237c66ac9dbSNicholas Bellinger } 2238c66ac9dbSNicholas Bellinger 2239c66ac9dbSNicholas Bellinger ssize_t core_alua_store_secondary_write_metadata( 2240c66ac9dbSNicholas Bellinger struct se_lun *lun, 2241c66ac9dbSNicholas Bellinger const char *page, 2242c66ac9dbSNicholas Bellinger size_t count) 2243c66ac9dbSNicholas Bellinger { 2244c66ac9dbSNicholas Bellinger unsigned long tmp; 2245c66ac9dbSNicholas Bellinger int ret; 2246c66ac9dbSNicholas Bellinger 224757103d7fSJingoo Han ret = kstrtoul(page, 0, &tmp); 2248c66ac9dbSNicholas Bellinger if (ret < 0) { 22496708bb27SAndy Grover pr_err("Unable to extract alua_tg_pt_write_md\n"); 225057103d7fSJingoo Han return ret; 2251c66ac9dbSNicholas Bellinger } 2252c66ac9dbSNicholas Bellinger if ((tmp != 0) && (tmp != 1)) { 22536708bb27SAndy Grover pr_err("Illegal value for alua_tg_pt_write_md:" 2254c66ac9dbSNicholas Bellinger " %lu\n", tmp); 2255c66ac9dbSNicholas Bellinger return -EINVAL; 2256c66ac9dbSNicholas Bellinger } 2257adf653f9SChristoph Hellwig lun->lun_tg_pt_secondary_write_md = (int)tmp; 2258c66ac9dbSNicholas Bellinger 2259c66ac9dbSNicholas Bellinger return count; 2260c66ac9dbSNicholas Bellinger } 2261c66ac9dbSNicholas Bellinger 22620fd97ccfSChristoph Hellwig int core_setup_alua(struct se_device *dev) 2263c66ac9dbSNicholas Bellinger { 226469088a04SBodo Stroesser if (!(dev->transport_flags & 2265530c6891SMike Christie TRANSPORT_FLAG_PASSTHROUGH_ALUA) && 2266c87fbd56SChristoph Hellwig !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { 2267c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp_member *lu_gp_mem; 22680fd97ccfSChristoph Hellwig 2269c66ac9dbSNicholas Bellinger /* 227025985edcSLucas De Marchi * Associate this struct se_device with the default ALUA 2271c66ac9dbSNicholas Bellinger * LUN Group. 2272c66ac9dbSNicholas Bellinger */ 2273c66ac9dbSNicholas Bellinger lu_gp_mem = core_alua_allocate_lu_gp_mem(dev); 2274e3d6f909SAndy Grover if (IS_ERR(lu_gp_mem)) 2275e3d6f909SAndy Grover return PTR_ERR(lu_gp_mem); 2276c66ac9dbSNicholas Bellinger 2277c66ac9dbSNicholas Bellinger spin_lock(&lu_gp_mem->lu_gp_mem_lock); 2278c66ac9dbSNicholas Bellinger __core_alua_attach_lu_gp_mem(lu_gp_mem, 2279e3d6f909SAndy Grover default_lu_gp); 2280c66ac9dbSNicholas Bellinger spin_unlock(&lu_gp_mem->lu_gp_mem_lock); 2281c66ac9dbSNicholas Bellinger 22826708bb27SAndy Grover pr_debug("%s: Adding to default ALUA LU Group:" 2283c66ac9dbSNicholas Bellinger " core/alua/lu_gps/default_lu_gp\n", 2284e3d6f909SAndy Grover dev->transport->name); 2285c66ac9dbSNicholas Bellinger } 2286c66ac9dbSNicholas Bellinger 2287c66ac9dbSNicholas Bellinger return 0; 2288c66ac9dbSNicholas Bellinger } 2289