aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2013-12-17 03:18:49 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2014-01-10 00:48:17 -0500
commitc66094bf325ee406b92298d73089ee25484a0263 (patch)
treecfa2fb231dbd3e120ad2d75f96c250c24233978a
parentfbfe858fea2a45df6339eb03dd1715b51f1bdc92 (diff)
target_core_alua: Referrals infrastructure
Add infrastructure for referrals. v2 changes: - Fix unsigned long long division in core_alua_state_lba_dependent on 32-bit (Fengguang + Chen + Hannes) - Fix compile warning in core_alua_state_lba_dependent (nab) - Convert segment_* + sectors variables in core_alua_state_lba_dependent to u64 (Hannes) Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_alua.c154
-rw-r--r--drivers/target/target_core_alua.h4
-rw-r--r--drivers/target/target_core_configfs.c9
-rw-r--r--drivers/target/target_core_device.c2
-rw-r--r--drivers/target/target_core_sbc.c5
-rw-r--r--drivers/target/target_core_spc.c20
-rw-r--r--include/scsi/scsi.h1
-rw-r--r--include/target/target_core_base.h18
8 files changed, 210 insertions, 3 deletions
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 01f0c71891d6..0843c8f4b94e 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -58,6 +58,75 @@ static LIST_HEAD(lu_gps_list);
58struct t10_alua_lu_gp *default_lu_gp; 58struct t10_alua_lu_gp *default_lu_gp;
59 59
60/* 60/*
61 * REPORT REFERRALS
62 *
63 * See sbc3r35 section 5.23
64 */
65sense_reason_t
66target_emulate_report_referrals(struct se_cmd *cmd)
67{
68 struct se_device *dev = cmd->se_dev;
69 struct t10_alua_lba_map *map;
70 struct t10_alua_lba_map_member *map_mem;
71 unsigned char *buf;
72 u32 rd_len = 0, off;
73
74 if (cmd->data_length < 4) {
75 pr_warn("REPORT REFERRALS allocation length %u too"
76 " small\n", cmd->data_length);
77 return TCM_INVALID_CDB_FIELD;
78 }
79
80 buf = transport_kmap_data_sg(cmd);
81 if (!buf)
82 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
83
84 off = 4;
85 spin_lock(&dev->t10_alua.lba_map_lock);
86 if (list_empty(&dev->t10_alua.lba_map_list)) {
87 spin_unlock(&dev->t10_alua.lba_map_lock);
88 transport_kunmap_data_sg(cmd);
89
90 return TCM_UNSUPPORTED_SCSI_OPCODE;
91 }
92
93 list_for_each_entry(map, &dev->t10_alua.lba_map_list,
94 lba_map_list) {
95 int desc_num = off + 3;
96 int pg_num;
97
98 off += 4;
99 put_unaligned_be64(map->lba_map_first_lba, &buf[off]);
100 off += 8;
101 put_unaligned_be64(map->lba_map_last_lba, &buf[off]);
102 off += 8;
103 rd_len += 20;
104 pg_num = 0;
105 list_for_each_entry(map_mem, &map->lba_map_mem_list,
106 lba_map_mem_list) {
107 buf[off++] = map_mem->lba_map_mem_alua_state & 0x0f;
108 off++;
109 buf[off++] = (map_mem->lba_map_mem_alua_pg_id >> 8) & 0xff;
110 buf[off++] = (map_mem->lba_map_mem_alua_pg_id & 0xff);
111 rd_len += 4;
112 pg_num++;
113 }
114 buf[desc_num] = pg_num;
115 }
116 spin_unlock(&dev->t10_alua.lba_map_lock);
117
118 /*
119 * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
120 */
121 put_unaligned_be16(rd_len, &buf[2]);
122
123 transport_kunmap_data_sg(cmd);
124
125 target_complete_cmd(cmd, GOOD);
126 return 0;
127}
128
129/*
61 * REPORT_TARGET_PORT_GROUPS 130 * REPORT_TARGET_PORT_GROUPS
62 * 131 *
63 * See spc4r17 section 6.27 132 * See spc4r17 section 6.27
@@ -391,6 +460,81 @@ static inline int core_alua_state_nonoptimized(
391 return 0; 460 return 0;
392} 461}
393 462
463static inline int core_alua_state_lba_dependent(
464 struct se_cmd *cmd,
465 struct t10_alua_tg_pt_gp *tg_pt_gp,
466 u8 *alua_ascq)
467{
468 struct se_device *dev = cmd->se_dev;
469 u64 segment_size, segment_mult, sectors, lba;
470
471 /* Only need to check for cdb actually containing LBAs */
472 if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB))
473 return 0;
474
475 spin_lock(&dev->t10_alua.lba_map_lock);
476 segment_size = dev->t10_alua.lba_map_segment_size;
477 segment_mult = dev->t10_alua.lba_map_segment_multiplier;
478 sectors = cmd->data_length / dev->dev_attrib.block_size;
479
480 lba = cmd->t_task_lba;
481 while (lba < cmd->t_task_lba + sectors) {
482 struct t10_alua_lba_map *cur_map = NULL, *map;
483 struct t10_alua_lba_map_member *map_mem;
484
485 list_for_each_entry(map, &dev->t10_alua.lba_map_list,
486 lba_map_list) {
487 u64 start_lba, last_lba;
488 u64 first_lba = map->lba_map_first_lba;
489
490 if (segment_mult) {
491 u64 tmp = lba;
492 start_lba = sector_div(tmp, segment_size * segment_mult);
493
494 last_lba = first_lba + segment_size - 1;
495 if (start_lba >= first_lba &&
496 start_lba <= last_lba) {
497 lba += segment_size;
498 cur_map = map;
499 break;
500 }
501 } else {
502 last_lba = map->lba_map_last_lba;
503 if (lba >= first_lba && lba <= last_lba) {
504 lba = last_lba + 1;
505 cur_map = map;
506 break;
507 }
508 }
509 }
510 if (!cur_map) {
511 spin_unlock(&dev->t10_alua.lba_map_lock);
512 *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
513 return 1;
514 }
515 list_for_each_entry(map_mem, &cur_map->lba_map_mem_list,
516 lba_map_mem_list) {
517 if (map_mem->lba_map_mem_alua_pg_id !=
518 tg_pt_gp->tg_pt_gp_id)
519 continue;
520 switch(map_mem->lba_map_mem_alua_state) {
521 case ALUA_ACCESS_STATE_STANDBY:
522 spin_unlock(&dev->t10_alua.lba_map_lock);
523 *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
524 return 1;
525 case ALUA_ACCESS_STATE_UNAVAILABLE:
526 spin_unlock(&dev->t10_alua.lba_map_lock);
527 *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
528 return 1;
529 default:
530 break;
531 }
532 }
533 }
534 spin_unlock(&dev->t10_alua.lba_map_lock);
535 return 0;
536}
537
394static inline int core_alua_state_standby( 538static inline int core_alua_state_standby(
395 struct se_cmd *cmd, 539 struct se_cmd *cmd,
396 unsigned char *cdb, 540 unsigned char *cdb,
@@ -588,6 +732,9 @@ target_alua_state_check(struct se_cmd *cmd)
588 case ALUA_ACCESS_STATE_TRANSITION: 732 case ALUA_ACCESS_STATE_TRANSITION:
589 ret = core_alua_state_transition(cmd, cdb, &alua_ascq); 733 ret = core_alua_state_transition(cmd, cdb, &alua_ascq);
590 break; 734 break;
735 case ALUA_ACCESS_STATE_LBA_DEPENDENT:
736 ret = core_alua_state_lba_dependent(cmd, tg_pt_gp, &alua_ascq);
737 break;
591 /* 738 /*
592 * OFFLINE is a secondary ALUA target port group access state, that is 739 * OFFLINE is a secondary ALUA target port group access state, that is
593 * handled above with struct se_port->sep_tg_pt_secondary_offline=1 740 * handled above with struct se_port->sep_tg_pt_secondary_offline=1
@@ -650,6 +797,11 @@ core_alua_check_transition(int state, int valid, int *primary)
650 goto not_supported; 797 goto not_supported;
651 *primary = 1; 798 *primary = 1;
652 break; 799 break;
800 case ALUA_ACCESS_STATE_LBA_DEPENDENT:
801 if (!(valid & ALUA_LBD_SUP))
802 goto not_supported;
803 *primary = 1;
804 break;
653 case ALUA_ACCESS_STATE_OFFLINE: 805 case ALUA_ACCESS_STATE_OFFLINE:
654 /* 806 /*
655 * OFFLINE state is defined as a secondary target port 807 * OFFLINE state is defined as a secondary target port
@@ -685,6 +837,8 @@ static char *core_alua_dump_state(int state)
685 return "Active/Optimized"; 837 return "Active/Optimized";
686 case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: 838 case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
687 return "Active/NonOptimized"; 839 return "Active/NonOptimized";
840 case ALUA_ACCESS_STATE_LBA_DEPENDENT:
841 return "LBA Dependent";
688 case ALUA_ACCESS_STATE_STANDBY: 842 case ALUA_ACCESS_STATE_STANDBY:
689 return "Standby"; 843 return "Standby";
690 case ALUA_ACCESS_STATE_UNAVAILABLE: 844 case ALUA_ACCESS_STATE_UNAVAILABLE:
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index 1a152cd59471..47950cdc6f8b 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -13,12 +13,13 @@
13/* 13/*
14 * ASYMMETRIC ACCESS STATE field 14 * ASYMMETRIC ACCESS STATE field
15 * 15 *
16 * from spc4r17 section 6.27 Table 245 16 * from spc4r36j section 6.37 Table 307
17 */ 17 */
18#define ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED 0x0 18#define ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED 0x0
19#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1 19#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
20#define ALUA_ACCESS_STATE_STANDBY 0x2 20#define ALUA_ACCESS_STATE_STANDBY 0x2
21#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3 21#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3
22#define ALUA_ACCESS_STATE_LBA_DEPENDENT 0x4
22#define ALUA_ACCESS_STATE_OFFLINE 0xe 23#define ALUA_ACCESS_STATE_OFFLINE 0xe
23#define ALUA_ACCESS_STATE_TRANSITION 0xf 24#define ALUA_ACCESS_STATE_TRANSITION 0xf
24 25
@@ -88,6 +89,7 @@ extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
88 89
89extern sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *); 90extern sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *);
90extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *); 91extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *);
92extern sense_reason_t target_emulate_report_referrals(struct se_cmd *);
91extern int core_alua_check_nonop_delay(struct se_cmd *); 93extern int core_alua_check_nonop_delay(struct se_cmd *);
92extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, 94extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
93 struct se_device *, struct se_port *, 95 struct se_device *, struct se_port *,
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index a1c23d10468e..e0a47f524700 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -2054,6 +2054,13 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
2054 " transition while TPGS_IMPLICIT_ALUA is disabled\n"); 2054 " transition while TPGS_IMPLICIT_ALUA is disabled\n");
2055 return -EINVAL; 2055 return -EINVAL;
2056 } 2056 }
2057 if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA &&
2058 new_state == ALUA_ACCESS_STATE_LBA_DEPENDENT) {
2059 /* LBA DEPENDENT is only allowed with implicit ALUA */
2060 pr_err("Unable to process implicit configfs ALUA transition"
2061 " while explicit ALUA management is enabled\n");
2062 return -EINVAL;
2063 }
2057 2064
2058 ret = core_alua_do_port_transition(tg_pt_gp, dev, 2065 ret = core_alua_do_port_transition(tg_pt_gp, dev,
2059 NULL, NULL, new_state, 0); 2066 NULL, NULL, new_state, 0);
@@ -2188,7 +2195,7 @@ SE_DEV_ALUA_SUPPORT_STATE_SHOW(lba_dependent,
2188 tg_pt_gp_alua_supported_states, ALUA_LBD_SUP); 2195 tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
2189SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent, 2196SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent,
2190 tg_pt_gp_alua_supported_states, ALUA_LBD_SUP); 2197 tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
2191SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO | S_IWUSR); 2198SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO);
2192 2199
2193SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable, 2200SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable,
2194 tg_pt_gp_alua_supported_states, ALUA_U_SUP); 2201 tg_pt_gp_alua_supported_states, ALUA_U_SUP);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index dbd78a176ddb..88b4fb2f6e1a 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -1439,6 +1439,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
1439 spin_lock_init(&dev->t10_pr.aptpl_reg_lock); 1439 spin_lock_init(&dev->t10_pr.aptpl_reg_lock);
1440 INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list); 1440 INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);
1441 spin_lock_init(&dev->t10_alua.tg_pt_gps_lock); 1441 spin_lock_init(&dev->t10_alua.tg_pt_gps_lock);
1442 INIT_LIST_HEAD(&dev->t10_alua.lba_map_list);
1443 spin_lock_init(&dev->t10_alua.lba_map_lock);
1442 1444
1443 dev->t10_wwn.t10_dev = dev; 1445 dev->t10_wwn.t10_dev = dev;
1444 dev->t10_alua.t10_dev = dev; 1446 dev->t10_alua.t10_dev = dev;
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 52ae54e60105..6863dbe0aadf 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -33,7 +33,7 @@
33 33
34#include "target_core_internal.h" 34#include "target_core_internal.h"
35#include "target_core_ua.h" 35#include "target_core_ua.h"
36 36#include "target_core_alua.h"
37 37
38static sense_reason_t 38static sense_reason_t
39sbc_emulate_readcapacity(struct se_cmd *cmd) 39sbc_emulate_readcapacity(struct se_cmd *cmd)
@@ -731,6 +731,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
731 case SAI_READ_CAPACITY_16: 731 case SAI_READ_CAPACITY_16:
732 cmd->execute_cmd = sbc_emulate_readcapacity_16; 732 cmd->execute_cmd = sbc_emulate_readcapacity_16;
733 break; 733 break;
734 case SAI_REPORT_REFERRALS:
735 cmd->execute_cmd = target_emulate_report_referrals;
736 break;
734 default: 737 default:
735 pr_err("Unsupported SA: 0x%02x\n", 738 pr_err("Unsupported SA: 0x%02x\n",
736 cmd->t_task_cdb[1] & 0x1f); 739 cmd->t_task_cdb[1] & 0x1f);
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 39054d9029f3..f9889fd82994 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -476,6 +476,11 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
476 /* If WriteCache emulation is enabled, set V_SUP */ 476 /* If WriteCache emulation is enabled, set V_SUP */
477 if (spc_check_dev_wce(dev)) 477 if (spc_check_dev_wce(dev))
478 buf[6] = 0x01; 478 buf[6] = 0x01;
479 /* If an LBA map is present set R_SUP */
480 spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
481 if (!list_empty(&dev->t10_alua.lba_map_list))
482 buf[8] = 0x10;
483 spin_unlock(&cmd->se_dev->t10_alua.lba_map_lock);
479 return 0; 484 return 0;
480} 485}
481 486
@@ -634,6 +639,20 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
634 return 0; 639 return 0;
635} 640}
636 641
642/* Referrals VPD page */
643static sense_reason_t
644spc_emulate_evpd_b3(struct se_cmd *cmd, unsigned char *buf)
645{
646 struct se_device *dev = cmd->se_dev;
647
648 buf[0] = dev->transport->get_device_type(dev);
649 buf[3] = 0x0c;
650 put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[8]);
651 put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[12]);
652
653 return 0;
654}
655
637static sense_reason_t 656static sense_reason_t
638spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); 657spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
639 658
@@ -648,6 +667,7 @@ static struct {
648 { .page = 0xb0, .emulate = spc_emulate_evpd_b0 }, 667 { .page = 0xb0, .emulate = spc_emulate_evpd_b0 },
649 { .page = 0xb1, .emulate = spc_emulate_evpd_b1 }, 668 { .page = 0xb1, .emulate = spc_emulate_evpd_b1 },
650 { .page = 0xb2, .emulate = spc_emulate_evpd_b2 }, 669 { .page = 0xb2, .emulate = spc_emulate_evpd_b2 },
670 { .page = 0xb3, .emulate = spc_emulate_evpd_b3 },
651}; 671};
652 672
653/* supported vital product data pages */ 673/* supported vital product data pages */
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 66d42edfb3fc..0a4edfe8af51 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -155,6 +155,7 @@ enum scsi_timeouts {
155/* values for service action in */ 155/* values for service action in */
156#define SAI_READ_CAPACITY_16 0x10 156#define SAI_READ_CAPACITY_16 0x10
157#define SAI_GET_LBA_STATUS 0x12 157#define SAI_GET_LBA_STATUS 0x12
158#define SAI_REPORT_REFERRALS 0x13
158/* values for VARIABLE_LENGTH_CMD service action codes 159/* values for VARIABLE_LENGTH_CMD service action codes
159 * see spc4r17 Section D.3.5, table D.7 and D.8 */ 160 * see spc4r17 Section D.3.5, table D.7 and D.8 */
160#define VLC_SA_RECEIVE_CREDENTIAL 0x1800 161#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 6c8001516c6d..1ba19a4bec33 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -247,10 +247,28 @@ typedef enum {
247 247
248struct se_cmd; 248struct se_cmd;
249 249
250struct t10_alua_lba_map_member {
251 struct list_head lba_map_mem_list;
252 int lba_map_mem_alua_state;
253 int lba_map_mem_alua_pg_id;
254};
255
256struct t10_alua_lba_map {
257 u64 lba_map_first_lba;
258 u64 lba_map_last_lba;
259 struct list_head lba_map_list;
260 struct list_head lba_map_mem_list;
261};
262
250struct t10_alua { 263struct t10_alua {
251 /* ALUA Target Port Group ID */ 264 /* ALUA Target Port Group ID */
252 u16 alua_tg_pt_gps_counter; 265 u16 alua_tg_pt_gps_counter;
253 u32 alua_tg_pt_gps_count; 266 u32 alua_tg_pt_gps_count;
267 /* Referrals support */
268 spinlock_t lba_map_lock;
269 u32 lba_map_segment_size;
270 u32 lba_map_segment_multiplier;
271 struct list_head lba_map_list;
254 spinlock_t tg_pt_gps_lock; 272 spinlock_t tg_pt_gps_lock;
255 struct se_device *t10_dev; 273 struct se_device *t10_dev;
256 /* Used for default ALUA Target Port Group */ 274 /* Used for default ALUA Target Port Group */