Skip to content

Commit aef2533

Browse files
committed
libnvdimm, nfit: centralize command status translation
The return value from an 'ndctl_fn' reports the command execution status, i.e. was the command properly formatted and was it successfully submitted to the bus provider. The new 'cmd_rc' parameter allows the bus provider to communicate command specific results, translated into common error codes. Convert the ARS commands to this scheme to: 1/ Consolidate status reporting 2/ Prepare for for expanding ars unit test cases 3/ Make the implementation more generic Cc: Vishal Verma <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent 3b87356 commit aef2533

File tree

6 files changed

+138
-67
lines changed

6 files changed

+138
-67
lines changed

drivers/acpi/nfit.c

Lines changed: 120 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,80 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
7272
return to_acpi_device(acpi_desc->dev);
7373
}
7474

75+
static int xlat_status(void *buf, unsigned int cmd)
76+
{
77+
struct nd_cmd_ars_status *ars_status;
78+
struct nd_cmd_ars_start *ars_start;
79+
struct nd_cmd_ars_cap *ars_cap;
80+
u16 flags;
81+
82+
switch (cmd) {
83+
case ND_CMD_ARS_CAP:
84+
ars_cap = buf;
85+
if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
86+
return -ENOTTY;
87+
88+
/* Command failed */
89+
if (ars_cap->status & 0xffff)
90+
return -EIO;
91+
92+
/* No supported scan types for this range */
93+
flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
94+
if ((ars_cap->status >> 16 & flags) == 0)
95+
return -ENOTTY;
96+
break;
97+
case ND_CMD_ARS_START:
98+
ars_start = buf;
99+
/* ARS is in progress */
100+
if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
101+
return -EBUSY;
102+
103+
/* Command failed */
104+
if (ars_start->status & 0xffff)
105+
return -EIO;
106+
break;
107+
case ND_CMD_ARS_STATUS:
108+
ars_status = buf;
109+
/* Command failed */
110+
if (ars_status->status & 0xffff)
111+
return -EIO;
112+
/* Check extended status (Upper two bytes) */
113+
if (ars_status->status == NFIT_ARS_STATUS_DONE)
114+
return 0;
115+
116+
/* ARS is in progress */
117+
if (ars_status->status == NFIT_ARS_STATUS_BUSY)
118+
return -EBUSY;
119+
120+
/* No ARS performed for the current boot */
121+
if (ars_status->status == NFIT_ARS_STATUS_NONE)
122+
return -EAGAIN;
123+
124+
/*
125+
* ARS interrupted, either we overflowed or some other
126+
* agent wants the scan to stop. If we didn't overflow
127+
* then just continue with the returned results.
128+
*/
129+
if (ars_status->status == NFIT_ARS_STATUS_INTR) {
130+
if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
131+
return -ENOSPC;
132+
return 0;
133+
}
134+
135+
/* Unknown status */
136+
if (ars_status->status >> 16)
137+
return -EIO;
138+
break;
139+
default:
140+
break;
141+
}
142+
143+
return 0;
144+
}
145+
75146
static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
76147
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
77-
unsigned int buf_len)
148+
unsigned int buf_len, int *cmd_rc)
78149
{
79150
struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
80151
const struct nd_cmd_desc *desc = NULL;
@@ -185,6 +256,8 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
185256
* unfilled in the output buffer
186257
*/
187258
rc = buf_len - offset - in_buf.buffer.length;
259+
if (cmd_rc)
260+
*cmd_rc = xlat_status(buf, cmd);
188261
} else {
189262
dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
190263
__func__, dimm_name, cmd_name, buf_len,
@@ -1105,7 +1178,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
11051178
writeq(cmd, mmio->addr.base + offset);
11061179
wmb_blk(nfit_blk);
11071180

1108-
if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH)
1181+
if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
11091182
readq(mmio->addr.base + offset);
11101183
}
11111184

@@ -1141,7 +1214,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
11411214
memcpy_to_pmem(mmio->addr.aperture + offset,
11421215
iobuf + copied, c);
11431216
else {
1144-
if (nfit_blk->dimm_flags & ND_BLK_READ_FLUSH)
1217+
if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH)
11451218
mmio_flush_range((void __force *)
11461219
mmio->addr.aperture + offset, c);
11471220

@@ -1328,13 +1401,13 @@ static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
13281401

13291402
memset(&flags, 0, sizeof(flags));
13301403
rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
1331-
sizeof(flags));
1404+
sizeof(flags), NULL);
13321405

13331406
if (rc >= 0 && flags.status == 0)
13341407
nfit_blk->dimm_flags = flags.flags;
13351408
else if (rc == -ENOTTY) {
13361409
/* fall back to a conservative default */
1337-
nfit_blk->dimm_flags = ND_BLK_DCR_LATCH | ND_BLK_READ_FLUSH;
1410+
nfit_blk->dimm_flags = NFIT_BLK_DCR_LATCH | NFIT_BLK_READ_FLUSH;
13381411
rc = 0;
13391412
} else
13401413
rc = -ENXIO;
@@ -1473,19 +1546,27 @@ static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus,
14731546
/* devm will free nfit_blk */
14741547
}
14751548

1476-
static int ars_get_cap(struct nvdimm_bus_descriptor *nd_desc,
1549+
static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
14771550
struct nd_cmd_ars_cap *cmd, u64 addr, u64 length)
14781551
{
1552+
struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
1553+
int cmd_rc, rc;
1554+
14791555
cmd->address = addr;
14801556
cmd->length = length;
1481-
1482-
return nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
1483-
sizeof(*cmd));
1557+
rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_CAP, cmd,
1558+
sizeof(*cmd), &cmd_rc);
1559+
if (rc < 0)
1560+
return rc;
1561+
if (cmd_rc < 0)
1562+
return cmd_rc;
1563+
return 0;
14841564
}
14851565

14861566
static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
14871567
struct nd_cmd_ars_start *cmd, u64 addr, u64 length)
14881568
{
1569+
int cmd_rc;
14891570
int rc;
14901571

14911572
cmd->address = addr;
@@ -1494,52 +1575,49 @@ static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
14941575

14951576
while (1) {
14961577
rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, cmd,
1497-
sizeof(*cmd));
1498-
if (rc)
1578+
sizeof(*cmd), &cmd_rc);
1579+
1580+
if (rc < 0)
14991581
return rc;
1500-
switch (cmd->status) {
1501-
case 0:
1502-
return 0;
1503-
case 1:
1504-
/* ARS unsupported, but we should never get here */
1505-
return 0;
1506-
case 6:
1582+
1583+
if (cmd_rc == -EBUSY) {
15071584
/* ARS is in progress */
15081585
msleep(1000);
1509-
break;
1510-
default:
1511-
return -ENXIO;
1586+
continue;
15121587
}
1588+
1589+
if (cmd_rc < 0)
1590+
return cmd_rc;
1591+
1592+
return 0;
15131593
}
15141594
}
15151595

15161596
static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc,
15171597
struct nd_cmd_ars_status *cmd, u32 size)
15181598
{
1519-
int rc;
1599+
int rc, cmd_rc;
15201600

15211601
while (1) {
15221602
rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, cmd,
1523-
size);
1524-
if (rc || cmd->status & 0xffff)
1525-
return -ENXIO;
1603+
size, &cmd_rc);
1604+
if (rc < 0)
1605+
return rc;
15261606

1527-
/* Check extended status (Upper two bytes) */
1528-
switch (cmd->status >> 16) {
1529-
case 0:
1530-
return 0;
1531-
case 1:
1532-
/* ARS is in progress */
1607+
/* FIXME make async and have a timeout */
1608+
if (cmd_rc == -EBUSY) {
15331609
msleep(1000);
1534-
break;
1535-
case 2:
1536-
/* No ARS performed for the current boot */
1610+
continue;
1611+
}
1612+
1613+
if (cmd_rc == -EAGAIN || cmd_rc == 0)
15371614
return 0;
1538-
case 3:
1539-
/* TODO: error list overflow support */
1540-
default:
1615+
1616+
/* TODO: error list overflow support */
1617+
if (cmd_rc == -ENOSPC)
15411618
return -ENXIO;
1542-
}
1619+
1620+
return cmd_rc;
15431621
}
15441622
}
15451623

@@ -1590,28 +1668,11 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
15901668
start = ndr_desc->res->start;
15911669
len = ndr_desc->res->end - ndr_desc->res->start + 1;
15921670

1593-
/*
1594-
* If ARS is unimplemented, unsupported, or if the 'Persistent Memory
1595-
* Scrub' flag in extended status is not set, skip this but continue
1596-
* initialization
1597-
*/
1598-
rc = ars_get_cap(nd_desc, ars_cap, start, len);
1671+
rc = ars_get_cap(acpi_desc, ars_cap, start, len);
15991672
if (rc == -ENOTTY) {
1600-
dev_dbg(acpi_desc->dev,
1601-
"Address Range Scrub is not implemented, won't create an error list\n");
16021673
rc = 0;
16031674
goto out;
16041675
}
1605-
if (rc)
1606-
goto out;
1607-
1608-
if ((ars_cap->status & 0xffff) ||
1609-
!(ars_cap->status >> 16 & ND_ARS_PERSISTENT)) {
1610-
dev_warn(acpi_desc->dev,
1611-
"ARS unsupported (status: 0x%x), won't create an error list\n",
1612-
ars_cap->status);
1613-
goto out;
1614-
}
16151676

16161677
/*
16171678
* Check if a full-range ARS has been run. If so, use those results
@@ -1651,15 +1712,15 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
16511712
u64 done, end;
16521713

16531714
rc = ars_do_start(nd_desc, ars_start, cur, remaining);
1654-
if (rc)
1715+
if (rc < 0)
16551716
goto out;
16561717

16571718
rc = ars_get_status(nd_desc, ars_status, ars_status_size);
1658-
if (rc)
1719+
if (rc < 0)
16591720
goto out;
16601721

16611722
rc = ars_status_process_records(nvdimm_bus, ars_status, cur);
1662-
if (rc)
1723+
if (rc < 0)
16631724
goto out;
16641725

16651726
end = min(cur + remaining,

drivers/acpi/nfit.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,15 @@ enum nfit_fic {
4747
};
4848

4949
enum {
50-
ND_BLK_READ_FLUSH = 1,
51-
ND_BLK_DCR_LATCH = 2,
50+
NFIT_BLK_READ_FLUSH = 1,
51+
NFIT_BLK_DCR_LATCH = 2,
52+
NFIT_ARS_STATUS_DONE = 0,
53+
NFIT_ARS_STATUS_BUSY = 1 << 16,
54+
NFIT_ARS_STATUS_NONE = 2 << 16,
55+
NFIT_ARS_STATUS_INTR = 3 << 16,
56+
NFIT_ARS_START_BUSY = 6,
57+
NFIT_ARS_CAP_NONE = 1,
58+
NFIT_ARS_F_OVERFLOW = 1,
5259
};
5360

5461
struct nfit_spa {

drivers/nvdimm/bus.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
587587
if (rc)
588588
goto out_unlock;
589589

590-
rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len);
590+
rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, NULL);
591591
if (rc < 0)
592592
goto out_unlock;
593593
if (copy_to_user(p, buf, buf_len))

drivers/nvdimm/dimm_devs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
7575
memset(cmd, 0, sizeof(*cmd));
7676
nd_desc = nvdimm_bus->nd_desc;
7777
return nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
78-
ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd));
78+
ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd), NULL);
7979
}
8080

8181
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
@@ -120,7 +120,7 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
120120
cmd->in_offset = offset;
121121
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
122122
ND_CMD_GET_CONFIG_DATA, cmd,
123-
cmd->in_length + sizeof(*cmd));
123+
cmd->in_length + sizeof(*cmd), NULL);
124124
if (rc || cmd->status) {
125125
rc = -ENXIO;
126126
break;
@@ -171,7 +171,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
171171
status = ((void *) cmd) + cmd_size - sizeof(u32);
172172

173173
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
174-
ND_CMD_SET_CONFIG_DATA, cmd, cmd_size);
174+
ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, NULL);
175175
if (rc || *status) {
176176
rc = rc ? rc : -ENXIO;
177177
break;

include/linux/libnvdimm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct nvdimm;
4848
struct nvdimm_bus_descriptor;
4949
typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
5050
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
51-
unsigned int buf_len);
51+
unsigned int buf_len, int *cmd_rc);
5252

5353
struct nd_namespace_label;
5454
struct nvdimm_drvdata;

tools/testing/nvdimm/test/nfit.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
261261

262262
static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
263263
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
264-
unsigned int buf_len)
264+
unsigned int buf_len, int *cmd_rc)
265265
{
266266
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
267267
struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc);
@@ -315,6 +315,9 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
315315
}
316316
}
317317

318+
/* TODO: error status tests */
319+
if (cmd_rc)
320+
*cmd_rc = 0;
318321
return rc;
319322
}
320323

0 commit comments

Comments
 (0)