Skip to content

Commit 71010c3

Browse files
Niklas CasselChristoph Hellwig
authored andcommitted
nvme: implement multiple I/O Command Set support
Implements support for multiple I/O Command Sets. NVMe TP 4056 introduces a method to enumerate multiple command sets per namespace. If the command set is exposed, this method for enumeration will be used instead of the traditional method that uses the CC.CSS register command set register for command set identification. For namespaces where the Command Set Identifier is not supported or recognized, the specific namespace will not be created. Reviewed-by: Javier González <javier.gonz@samsung.com> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Matias Bjørling <matias.bjorling@wdc.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 089565f commit 71010c3

File tree

3 files changed

+61
-12
lines changed

3 files changed

+61
-12
lines changed

drivers/nvme/host/core.c

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,8 +1056,13 @@ static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
10561056
return error;
10571057
}
10581058

1059+
static bool nvme_multi_css(struct nvme_ctrl *ctrl)
1060+
{
1061+
return (ctrl->ctrl_config & NVME_CC_CSS_MASK) == NVME_CC_CSS_CSI;
1062+
}
1063+
10591064
static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids *ids,
1060-
struct nvme_ns_id_desc *cur)
1065+
struct nvme_ns_id_desc *cur, bool *csi_seen)
10611066
{
10621067
const char *warn_str = "ctrl returned bogus length:";
10631068
void *data = cur;
@@ -1087,6 +1092,15 @@ static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids *ids,
10871092
}
10881093
uuid_copy(&ids->uuid, data + sizeof(*cur));
10891094
return NVME_NIDT_UUID_LEN;
1095+
case NVME_NIDT_CSI:
1096+
if (cur->nidl != NVME_NIDT_CSI_LEN) {
1097+
dev_warn(ctrl->device, "%s %d for NVME_NIDT_CSI\n",
1098+
warn_str, cur->nidl);
1099+
return -1;
1100+
}
1101+
memcpy(&ids->csi, data + sizeof(*cur), NVME_NIDT_CSI_LEN);
1102+
*csi_seen = true;
1103+
return NVME_NIDT_CSI_LEN;
10901104
default:
10911105
/* Skip unknown types */
10921106
return cur->nidl;
@@ -1097,10 +1111,9 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
10971111
struct nvme_ns_ids *ids)
10981112
{
10991113
struct nvme_command c = { };
1100-
int status;
1114+
bool csi_seen = false;
1115+
int status, pos, len;
11011116
void *data;
1102-
int pos;
1103-
int len;
11041117

11051118
c.identify.opcode = nvme_admin_identify;
11061119
c.identify.nsid = cpu_to_le32(nsid);
@@ -1125,7 +1138,7 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
11251138
* device just because of a temporal retry-able error (such
11261139
* as path of transport errors).
11271140
*/
1128-
if (status > 0 && (status & NVME_SC_DNR))
1141+
if (status > 0 && (status & NVME_SC_DNR) && !nvme_multi_css(ctrl))
11291142
status = 0;
11301143
goto free_data;
11311144
}
@@ -1136,12 +1149,19 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
11361149
if (cur->nidl == 0)
11371150
break;
11381151

1139-
len = nvme_process_ns_desc(ctrl, ids, cur);
1152+
len = nvme_process_ns_desc(ctrl, ids, cur, &csi_seen);
11401153
if (len < 0)
1141-
goto free_data;
1154+
break;
11421155

11431156
len += sizeof(*cur);
11441157
}
1158+
1159+
if (nvme_multi_css(ctrl) && !csi_seen) {
1160+
dev_warn(ctrl->device, "Command set not reported for nsid:%d\n",
1161+
nsid);
1162+
status = -EINVAL;
1163+
}
1164+
11451165
free_data:
11461166
kfree(data);
11471167
return status;
@@ -1798,7 +1818,7 @@ static int nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid,
17981818
memcpy(ids->eui64, id->eui64, sizeof(id->eui64));
17991819
if (ctrl->vs >= NVME_VS(1, 2, 0))
18001820
memcpy(ids->nguid, id->nguid, sizeof(id->nguid));
1801-
if (ctrl->vs >= NVME_VS(1, 3, 0))
1821+
if (ctrl->vs >= NVME_VS(1, 3, 0) || nvme_multi_css(ctrl))
18021822
return nvme_identify_ns_descs(ctrl, nsid, ids);
18031823
return 0;
18041824
}
@@ -1814,7 +1834,8 @@ static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
18141834
{
18151835
return uuid_equal(&a->uuid, &b->uuid) &&
18161836
memcmp(&a->nguid, &b->nguid, sizeof(a->nguid)) == 0 &&
1817-
memcmp(&a->eui64, &b->eui64, sizeof(a->eui64)) == 0;
1837+
memcmp(&a->eui64, &b->eui64, sizeof(a->eui64)) == 0 &&
1838+
a->csi == b->csi;
18181839
}
18191840

18201841
static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
@@ -1936,6 +1957,15 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
19361957
if (ns->lba_shift == 0)
19371958
ns->lba_shift = 9;
19381959

1960+
switch (ns->head->ids.csi) {
1961+
case NVME_CSI_NVM:
1962+
break;
1963+
default:
1964+
dev_warn(ctrl->device, "unknown csi:%d ns:%d\n",
1965+
ns->head->ids.csi, ns->head->ns_id);
1966+
return -ENODEV;
1967+
}
1968+
19391969
if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
19401970
is_power_of_2(ctrl->max_hw_sectors))
19411971
iob = ctrl->max_hw_sectors;
@@ -2270,7 +2300,10 @@ int nvme_enable_ctrl(struct nvme_ctrl *ctrl)
22702300

22712301
ctrl->page_size = 1 << page_shift;
22722302

2273-
ctrl->ctrl_config = NVME_CC_CSS_NVM;
2303+
if (NVME_CAP_CSS(ctrl->cap) & NVME_CAP_CSS_CSI)
2304+
ctrl->ctrl_config = NVME_CC_CSS_CSI;
2305+
else
2306+
ctrl->ctrl_config = NVME_CC_CSS_NVM;
22742307
ctrl->ctrl_config |= (page_shift - 12) << NVME_CC_MPS_SHIFT;
22752308
ctrl->ctrl_config |= NVME_CC_AMS_RR | NVME_CC_SHN_NONE;
22762309
ctrl->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;

drivers/nvme/host/nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ struct nvme_ns_ids {
339339
u8 eui64[8];
340340
u8 nguid[16];
341341
uuid_t uuid;
342+
u8 csi;
342343
};
343344

344345
/*

include/linux/nvme.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ enum {
132132
#define NVME_CAP_TIMEOUT(cap) (((cap) >> 24) & 0xff)
133133
#define NVME_CAP_STRIDE(cap) (((cap) >> 32) & 0xf)
134134
#define NVME_CAP_NSSRC(cap) (((cap) >> 36) & 0x1)
135+
#define NVME_CAP_CSS(cap) (((cap) >> 37) & 0xff)
135136
#define NVME_CAP_MPSMIN(cap) (((cap) >> 48) & 0xf)
136137
#define NVME_CAP_MPSMAX(cap) (((cap) >> 52) & 0xf)
137138

@@ -162,14 +163,16 @@ enum {
162163

163164
enum {
164165
NVME_CC_ENABLE = 1 << 0,
165-
NVME_CC_CSS_NVM = 0 << 4,
166166
NVME_CC_EN_SHIFT = 0,
167167
NVME_CC_CSS_SHIFT = 4,
168168
NVME_CC_MPS_SHIFT = 7,
169169
NVME_CC_AMS_SHIFT = 11,
170170
NVME_CC_SHN_SHIFT = 14,
171171
NVME_CC_IOSQES_SHIFT = 16,
172172
NVME_CC_IOCQES_SHIFT = 20,
173+
NVME_CC_CSS_NVM = 0 << NVME_CC_CSS_SHIFT,
174+
NVME_CC_CSS_CSI = 6 << NVME_CC_CSS_SHIFT,
175+
NVME_CC_CSS_MASK = 7 << NVME_CC_CSS_SHIFT,
173176
NVME_CC_AMS_RR = 0 << NVME_CC_AMS_SHIFT,
174177
NVME_CC_AMS_WRRU = 1 << NVME_CC_AMS_SHIFT,
175178
NVME_CC_AMS_VS = 7 << NVME_CC_AMS_SHIFT,
@@ -179,6 +182,8 @@ enum {
179182
NVME_CC_SHN_MASK = 3 << NVME_CC_SHN_SHIFT,
180183
NVME_CC_IOSQES = NVME_NVM_IOSQES << NVME_CC_IOSQES_SHIFT,
181184
NVME_CC_IOCQES = NVME_NVM_IOCQES << NVME_CC_IOCQES_SHIFT,
185+
NVME_CAP_CSS_NVM = 1 << 0,
186+
NVME_CAP_CSS_CSI = 1 << 6,
182187
NVME_CSTS_RDY = 1 << 0,
183188
NVME_CSTS_CFS = 1 << 1,
184189
NVME_CSTS_NSSRO = 1 << 4,
@@ -374,6 +379,8 @@ enum {
374379
NVME_ID_CNS_CTRL = 0x01,
375380
NVME_ID_CNS_NS_ACTIVE_LIST = 0x02,
376381
NVME_ID_CNS_NS_DESC_LIST = 0x03,
382+
NVME_ID_CNS_CS_NS = 0x05,
383+
NVME_ID_CNS_CS_CTRL = 0x06,
377384
NVME_ID_CNS_NS_PRESENT_LIST = 0x10,
378385
NVME_ID_CNS_NS_PRESENT = 0x11,
379386
NVME_ID_CNS_CTRL_NS_LIST = 0x12,
@@ -383,6 +390,10 @@ enum {
383390
NVME_ID_CNS_UUID_LIST = 0x17,
384391
};
385392

393+
enum {
394+
NVME_CSI_NVM = 0,
395+
};
396+
386397
enum {
387398
NVME_DIR_IDENTIFY = 0x00,
388399
NVME_DIR_STREAMS = 0x01,
@@ -435,11 +446,13 @@ struct nvme_ns_id_desc {
435446
#define NVME_NIDT_EUI64_LEN 8
436447
#define NVME_NIDT_NGUID_LEN 16
437448
#define NVME_NIDT_UUID_LEN 16
449+
#define NVME_NIDT_CSI_LEN 1
438450

439451
enum {
440452
NVME_NIDT_EUI64 = 0x01,
441453
NVME_NIDT_NGUID = 0x02,
442454
NVME_NIDT_UUID = 0x03,
455+
NVME_NIDT_CSI = 0x04,
443456
};
444457

445458
struct nvme_smart_log {
@@ -972,7 +985,9 @@ struct nvme_identify {
972985
__u8 cns;
973986
__u8 rsvd3;
974987
__le16 ctrlid;
975-
__u32 rsvd11[5];
988+
__u8 rsvd11[3];
989+
__u8 csi;
990+
__u32 rsvd12[4];
976991
};
977992

978993
#define NVME_IDENTIFY_DATA_SIZE 4096

0 commit comments

Comments
 (0)