[PATCH] NVMe: Read-Write Error Recovery mode page
Sathyavathi M
sathya.m at samsung.com
Tue Jul 28 02:48:32 PDT 2015
This patch implements the SCSI to NVMe translation for Read Write Error
Recovery mode page, as defined by the SCSI translation specification version 1.4
Signed-off-by: Sathyavathi M <sathya.m at samsung.com>
---
drivers/block/nvme-scsi.c | 61 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 57 insertions(+), 4 deletions(-)
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c
index e5a63f0..5333c31 100644
--- a/drivers/block/nvme-scsi.c
+++ b/drivers/block/nvme-scsi.c
@@ -108,6 +108,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define RESERVED_FIELD 0
/* Mode Sense/Select defines */
+#define MODE_PAGE_RW_ERR_RECOVERY 0x01
#define MODE_PAGE_INFO_EXCEP 0x1C
#define MODE_PAGE_CACHING 0x08
#define MODE_PAGE_CONTROL 0x0A
@@ -115,11 +116,12 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define MODE_PAGE_RETURN_ALL 0x3F
#define MODE_PAGE_BLK_DES_LEN 0x08
#define MODE_PAGE_LLBAA_BLK_DES_LEN 0x10
+#define MODE_PAGE_RW_ERR_RECOVERY_LEN 0x0C
#define MODE_PAGE_CACHING_LEN 0x14
#define MODE_PAGE_CONTROL_LEN 0x0C
#define MODE_PAGE_POW_CND_LEN 0x28
#define MODE_PAGE_INF_EXC_LEN 0x0C
-#define MODE_PAGE_ALL_LEN 0x54
+#define MODE_PAGE_ALL_LEN 0x60
#define MODE_SENSE6_MPH_SIZE 4
#define MODE_SENSE_PAGE_CONTROL_MASK 0xC0
#define MODE_SENSE_PAGE_CODE_OFFSET 2
@@ -143,6 +145,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define MODE_SELECT_PAGE_CODE_MASK 0x3F
#define SHORT_DESC_BLOCK 8
#define LONG_DESC_BLOCK 16
+#define MODE_PAGE_RW_ERR_RECOVERY_LEN_FILED 0x0A
#define MODE_PAGE_POW_CND_LEN_FIELD 0x26
#define MODE_PAGE_INF_EXC_LEN_FIELD 0x0A
#define MODE_PAGE_CACHING_LEN_FIELD 0x12
@@ -919,6 +922,34 @@ static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr,
/* MODE SENSE Helper Functions */
+static int nvme_trans_fill_rw_err_recovery_page(struct nvme_ns *ns,
+ struct sg_io_hdr *hdr, u8 *resp, int len)
+{
+ int res = SNTI_TRANSLATION_SUCCESS;
+ int nvme_sc;
+ struct nvme_dev *dev = ns->dev;
+ u32 feature_resp;
+ u16 tler;
+
+ if (len < MODE_PAGE_RW_ERR_RECOVERY_LEN)
+ return SNTI_INTERNAL_ERROR;
+
+ nvme_sc = nvme_get_features(dev, NVME_FEAT_ERR_RECOVERY, 0, 0,
+ &feature_resp);
+ res = nvme_trans_status_code(hdr, nvme_sc);
+ if (res)
+ return res;
+ tler = (feature_resp & 0xFFFF) * 0x100;
+ resp[0] = MODE_PAGE_RW_ERR_RECOVERY;
+ resp[1] = MODE_PAGE_RW_ERR_RECOVERY_LEN_FILED;
+ resp[2] = 0xC0; /* DCR=0, DTE=0, PER=0, EER=0
+ * RC=0, TB=0, ARRE=1, AWRE=1 */
+ resp[10] = ((tler & 0xFF00) >> 8);
+ resp[11] = tler & 0xFF;
+
+ return res;
+}
+
static int nvme_trans_fill_mode_parm_hdr(u8 *resp, int len, u8 cdb10, u8 llbaa,
u16 mode_data_length, u16 blk_desc_len)
{
@@ -1069,11 +1100,13 @@ static int nvme_trans_fill_all_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
{
int res;
u16 mode_pages_offset_1 = 0;
- u16 mode_pages_offset_2, mode_pages_offset_3, mode_pages_offset_4;
+ u16 mode_pages_offset_2, mode_pages_offset_3, mode_pages_offset_4,
+ mode_pages_offset_5;
mode_pages_offset_2 = mode_pages_offset_1 + MODE_PAGE_CACHING_LEN;
mode_pages_offset_3 = mode_pages_offset_2 + MODE_PAGE_CONTROL_LEN;
mode_pages_offset_4 = mode_pages_offset_3 + MODE_PAGE_POW_CND_LEN;
+ mode_pages_offset_5 = mode_pages_offset_4 + MODE_PAGE_INF_EXC_LEN;
res = nvme_trans_fill_caching_page(ns, hdr, &resp[mode_pages_offset_1],
MODE_PAGE_CACHING_LEN);
@@ -1087,8 +1120,13 @@ static int nvme_trans_fill_all_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
MODE_PAGE_POW_CND_LEN);
if (res)
return res;
- return nvme_trans_fill_inf_exc_page(ns, hdr, &resp[mode_pages_offset_4],
+ res = nvme_trans_fill_inf_exc_page(ns, hdr, &resp[mode_pages_offset_4],
MODE_PAGE_INF_EXC_LEN);
+ if (res)
+ return res;
+
+ return nvme_trans_fill_rw_err_recovery_page(ns, hdr,
+ &resp[mode_pages_offset_5], MODE_PAGE_RW_ERR_RECOVERY_LEN);
}
static inline int nvme_trans_get_blk_desc_len(u8 dbd, u8 llbaa)
@@ -1368,6 +1406,14 @@ static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
unsigned dword11;
switch (page_code) {
+ case MODE_PAGE_RW_ERR_RECOVERY:
+ dword11 = mode_page[11];
+ dword11 |= (mode_page[10] << 8);
+ dword11 = dword11 / 100;
+ nvme_sc = nvme_set_features(dev, NVME_FEAT_ERR_RECOVERY,
+ dword11, 0, NULL);
+ res = nvme_trans_status_code(hdr, nvme_sc);
+ break;
case MODE_PAGE_CACHING:
dword11 = ((mode_page[2] & CACHING_MODE_PAGE_WCE_MASK) ? 1 : 0);
nvme_sc = nvme_set_features(dev, NVME_FEAT_VOLATILE_WC, dword11,
@@ -1435,7 +1481,8 @@ static int nvme_trans_modesel_data(struct nvme_ns *ns, struct sg_io_hdr *hdr,
do {
page_code = parm_list[index] & MODE_SELECT_PAGE_CODE_MASK;
mp_size = parm_list[index + 1] + 2;
- if ((page_code != MODE_PAGE_CACHING) &&
+ if ((page_code != MODE_PAGE_RW_ERR_RECOVERY) &&
+ (page_code != MODE_PAGE_CACHING) &&
(page_code != MODE_PAGE_CONTROL) &&
(page_code != MODE_PAGE_POWER_CONDITION)) {
res = nvme_trans_completion(hdr,
@@ -1991,6 +2038,12 @@ static int nvme_trans_mode_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
}
switch (cmd[2] & MODE_SENSE_PAGE_CODE_MASK) {
+ case MODE_PAGE_RW_ERR_RECOVERY:
+ res = nvme_trans_mode_page_create(ns, hdr, cmd, alloc_len,
+ cdb10,
+ &nvme_trans_fill_rw_err_recovery_page,
+ MODE_PAGE_RW_ERR_RECOVERY_LEN);
+ break;
case MODE_PAGE_CACHING:
res = nvme_trans_mode_page_create(ns, hdr, cmd, alloc_len,
cdb10,
--
1.9.1
More information about the Linux-nvme
mailing list