Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

target: Add MI_REPORT_TARGET_PGS ext. header + implict_trans_secs attribute

This patch adds support for ALUA MI_REPORT_TARGET_PGS extended header
format defined within SPC-4. It changes target core ALUA emulation logic
within target_emulate_report_target_port_groups() to support both the
extended and original length only header formats.

It includes adding a new 'implict_trans_secs' attribute for each ALUA
target port group to control the value returned to the application client
for an recommended implict translation timeout in seconds. By default
this value is currently set to zero, and limited up to 255 by virtue of
using a single byte in the extended header format.

This value is used by target_emulate_report_target_port_groups() within
the extended header logic to set IMPLICIT TRANSITION TIME as defined by
spc4r30.

Cc: Hannes Reinecke <hare@suse.de>
Cc: Rob Evers <revers@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>

+102 -12
+70 -12
drivers/target/target_core_alua.c
··· 66 66 struct t10_alua_tg_pt_gp *tg_pt_gp; 67 67 struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; 68 68 unsigned char *buf; 69 - u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first 70 - Target port group descriptor */ 69 + u32 rd_len = 0, off; 70 + int ext_hdr = (cmd->t_task_cdb[1] & 0x20); 71 71 /* 72 - * Need at least 4 bytes of response data or else we can't 73 - * even fit the return data length. 72 + * Skip over RESERVED area to first Target port group descriptor 73 + * depending on the PARAMETER DATA FORMAT type.. 74 74 */ 75 - if (cmd->data_length < 4) { 76 - pr_warn("REPORT TARGET PORT GROUPS allocation length %u" 77 - " too small\n", cmd->data_length); 75 + if (ext_hdr != 0) 76 + off = 8; 77 + else 78 + off = 4; 79 + 80 + if (cmd->data_length < off) { 81 + pr_warn("REPORT TARGET PORT GROUPS allocation length %u too" 82 + " small for %s header\n", cmd->data_length, 83 + (ext_hdr) ? "extended" : "normal"); 84 + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; 78 85 return -EINVAL; 79 86 } 80 - 81 87 buf = transport_kmap_data_sg(cmd); 82 88 83 89 spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); ··· 164 158 /* 165 159 * Set the RETURN DATA LENGTH set in the header of the DataIN Payload 166 160 */ 167 - buf[0] = ((rd_len >> 24) & 0xff); 168 - buf[1] = ((rd_len >> 16) & 0xff); 169 - buf[2] = ((rd_len >> 8) & 0xff); 170 - buf[3] = (rd_len & 0xff); 161 + put_unaligned_be32(rd_len, &buf[0]); 171 162 163 + /* 164 + * Fill in the Extended header parameter data format if requested 165 + */ 166 + if (ext_hdr != 0) { 167 + buf[4] = 0x10; 168 + /* 169 + * Set the implict transition time (in seconds) for the application 170 + * client to use as a base for it's transition timeout value. 171 + * 172 + * Use the current tg_pt_gp_mem -> tg_pt_gp membership from the LUN 173 + * this CDB was received upon to determine this value individually 174 + * for ALUA target port group. 175 + */ 176 + port = cmd->se_lun->lun_sep; 177 + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; 178 + if (tg_pt_gp_mem) { 179 + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); 180 + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; 181 + if (tg_pt_gp) 182 + buf[5] = tg_pt_gp->tg_pt_gp_implict_trans_secs; 183 + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); 184 + } 185 + } 172 186 transport_kunmap_data_sg(cmd); 173 187 174 188 target_complete_cmd(cmd, GOOD); ··· 1381 1355 */ 1382 1356 tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS; 1383 1357 tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; 1358 + tg_pt_gp->tg_pt_gp_implict_trans_secs = ALUA_DEFAULT_IMPLICT_TRANS_SECS; 1384 1359 1385 1360 if (def_group) { 1386 1361 spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); ··· 1874 1847 return -EINVAL; 1875 1848 } 1876 1849 tg_pt_gp->tg_pt_gp_trans_delay_msecs = (int)tmp; 1850 + 1851 + return count; 1852 + } 1853 + 1854 + ssize_t core_alua_show_implict_trans_secs( 1855 + struct t10_alua_tg_pt_gp *tg_pt_gp, 1856 + char *page) 1857 + { 1858 + return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_implict_trans_secs); 1859 + } 1860 + 1861 + ssize_t core_alua_store_implict_trans_secs( 1862 + struct t10_alua_tg_pt_gp *tg_pt_gp, 1863 + const char *page, 1864 + size_t count) 1865 + { 1866 + unsigned long tmp; 1867 + int ret; 1868 + 1869 + ret = strict_strtoul(page, 0, &tmp); 1870 + if (ret < 0) { 1871 + pr_err("Unable to extract implict_trans_secs\n"); 1872 + return -EINVAL; 1873 + } 1874 + if (tmp > ALUA_MAX_IMPLICT_TRANS_SECS) { 1875 + pr_err("Passed implict_trans_secs: %lu, exceeds" 1876 + " ALUA_MAX_IMPLICT_TRANS_SECS: %d\n", tmp, 1877 + ALUA_MAX_IMPLICT_TRANS_SECS); 1878 + return -EINVAL; 1879 + } 1880 + tg_pt_gp->tg_pt_gp_implict_trans_secs = (int)tmp; 1877 1881 1878 1882 return count; 1879 1883 }
+10
drivers/target/target_core_alua.h
··· 52 52 #define ALUA_DEFAULT_TRANS_DELAY_MSECS 0 53 53 #define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */ 54 54 /* 55 + * Used for the recommended application client implict transition timeout 56 + * in seconds, returned by the REPORT_TARGET_PORT_GROUPS w/ extended header. 57 + */ 58 + #define ALUA_DEFAULT_IMPLICT_TRANS_SECS 0 59 + #define ALUA_MAX_IMPLICT_TRANS_SECS 255 60 + /* 55 61 * Used by core_alua_update_tpg_primary_metadata() and 56 62 * core_alua_update_tpg_secondary_metadata() 57 63 */ ··· 112 106 extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *, 113 107 char *); 114 108 extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *, 109 + const char *, size_t); 110 + extern ssize_t core_alua_show_implict_trans_secs(struct t10_alua_tg_pt_gp *, 111 + char *); 112 + extern ssize_t core_alua_store_implict_trans_secs(struct t10_alua_tg_pt_gp *, 115 113 const char *, size_t); 116 114 extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *, 117 115 char *);
+21
drivers/target/target_core_configfs.c
··· 2447 2447 SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR); 2448 2448 2449 2449 /* 2450 + * implict_trans_secs 2451 + */ 2452 + static ssize_t target_core_alua_tg_pt_gp_show_attr_implict_trans_secs( 2453 + struct t10_alua_tg_pt_gp *tg_pt_gp, 2454 + char *page) 2455 + { 2456 + return core_alua_show_implict_trans_secs(tg_pt_gp, page); 2457 + } 2458 + 2459 + static ssize_t target_core_alua_tg_pt_gp_store_attr_implict_trans_secs( 2460 + struct t10_alua_tg_pt_gp *tg_pt_gp, 2461 + const char *page, 2462 + size_t count) 2463 + { 2464 + return core_alua_store_implict_trans_secs(tg_pt_gp, page, count); 2465 + } 2466 + 2467 + SE_DEV_ALUA_TG_PT_ATTR(implict_trans_secs, S_IRUGO | S_IWUSR); 2468 + 2469 + /* 2450 2470 * preferred 2451 2471 */ 2452 2472 ··· 2590 2570 &target_core_alua_tg_pt_gp_alua_write_metadata.attr, 2591 2571 &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, 2592 2572 &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, 2573 + &target_core_alua_tg_pt_gp_implict_trans_secs.attr, 2593 2574 &target_core_alua_tg_pt_gp_preferred.attr, 2594 2575 &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr, 2595 2576 &target_core_alua_tg_pt_gp_members.attr,
+1
include/target/target_core_base.h
··· 330 330 int tg_pt_gp_alua_access_type; 331 331 int tg_pt_gp_nonop_delay_msecs; 332 332 int tg_pt_gp_trans_delay_msecs; 333 + int tg_pt_gp_implict_trans_secs; 333 334 int tg_pt_gp_pref; 334 335 int tg_pt_gp_write_metadata; 335 336 /* Used by struct t10_alua_tg_pt_gp->tg_pt_gp_md_buf_len */