Skip to content

Commit bd4da3a

Browse files
amlutoaxboe
authored andcommitted
nvme: Add a quirk mechanism that uses identify_ctrl
Currently, all NVMe quirks are based on PCI IDs. Add a mechanism to define quirks based on identify_ctrl's vendor id, model number, and/or firmware revision. Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Andy Lutomirski <[email protected]> Signed-off-by: Sagi Grimberg <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent e5a39dd commit bd4da3a

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

drivers/nvme/host/core.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,50 @@ static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
12521252
blk_queue_write_cache(q, vwc, vwc);
12531253
}
12541254

1255+
struct nvme_core_quirk_entry {
1256+
/*
1257+
* NVMe model and firmware strings are padded with spaces. For
1258+
* simplicity, strings in the quirk table are padded with NULLs
1259+
* instead.
1260+
*/
1261+
u16 vid;
1262+
const char *mn;
1263+
const char *fr;
1264+
unsigned long quirks;
1265+
};
1266+
1267+
static const struct nvme_core_quirk_entry core_quirks[] = {
1268+
};
1269+
1270+
/* match is null-terminated but idstr is space-padded. */
1271+
static bool string_matches(const char *idstr, const char *match, size_t len)
1272+
{
1273+
size_t matchlen;
1274+
1275+
if (!match)
1276+
return true;
1277+
1278+
matchlen = strlen(match);
1279+
WARN_ON_ONCE(matchlen > len);
1280+
1281+
if (memcmp(idstr, match, matchlen))
1282+
return false;
1283+
1284+
for (; matchlen < len; matchlen++)
1285+
if (idstr[matchlen] != ' ')
1286+
return false;
1287+
1288+
return true;
1289+
}
1290+
1291+
static bool quirk_matches(const struct nvme_id_ctrl *id,
1292+
const struct nvme_core_quirk_entry *q)
1293+
{
1294+
return q->vid == le16_to_cpu(id->vid) &&
1295+
string_matches(id->mn, q->mn, sizeof(id->mn)) &&
1296+
string_matches(id->fr, q->fr, sizeof(id->fr));
1297+
}
1298+
12551299
/*
12561300
* Initialize the cached copies of the Identify data and various controller
12571301
* register in our nvme_ctrl structure. This should be called as soon as
@@ -1286,6 +1330,24 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
12861330
return -EIO;
12871331
}
12881332

1333+
if (!ctrl->identified) {
1334+
/*
1335+
* Check for quirks. Quirk can depend on firmware version,
1336+
* so, in principle, the set of quirks present can change
1337+
* across a reset. As a possible future enhancement, we
1338+
* could re-scan for quirks every time we reinitialize
1339+
* the device, but we'd have to make sure that the driver
1340+
* behaves intelligently if the quirks change.
1341+
*/
1342+
1343+
int i;
1344+
1345+
for (i = 0; i < ARRAY_SIZE(core_quirks); i++) {
1346+
if (quirk_matches(id, &core_quirks[i]))
1347+
ctrl->quirks |= core_quirks[i].quirks;
1348+
}
1349+
}
1350+
12891351
ctrl->oacs = le16_to_cpu(id->oacs);
12901352
ctrl->vid = le16_to_cpu(id->vid);
12911353
ctrl->oncs = le16_to_cpup(&id->oncs);
@@ -1329,6 +1391,8 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
13291391
}
13301392

13311393
kfree(id);
1394+
1395+
ctrl->identified = true;
13321396
return ret;
13331397
}
13341398
EXPORT_SYMBOL_GPL(nvme_init_identify);

drivers/nvme/host/nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ enum nvme_ctrl_state {
112112

113113
struct nvme_ctrl {
114114
enum nvme_ctrl_state state;
115+
bool identified;
115116
spinlock_t lock;
116117
const struct nvme_ctrl_ops *ops;
117118
struct request_queue *admin_q;

0 commit comments

Comments
 (0)