NVMe: write_long SCSI to NVMe translation implementation
Subsystems (2)
PATCH v2 1/1 NVMe: write_long SCSI to NVMe translation implementation
From: Sunad Bhandary S <[email protected]>
This patch implements the SCSI to NVMe translation for write_long. write_long is translated to the NVMe command write_uncorrectable as defined by the translation specification version 1.4.
This patch also indicates the device support for write_uncorrectable method in the response of extended inquiry as defined in the translation spec.
This patch is based on for-linus branch.
Changes:
v1 -> v2 : __le32 nlb field changed to __le16 nlb followed by __u16 rsvd.
--- drivers/block/nvme-scsi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++-- include/uapi/linux/nvme.h | 13 ++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-)
drivers/block/nvme-scsi.c +64 -2
@@ -245,6 +245,15 @@ static int sg_version_num = 30534; /* 2 digits for each component *//* Report LUNs defines */ #define REPORT_LUNS_FIRST_LUN_OFFSET 8 +/*Write Long defines */ +#define WRITE_LONG_CDB_COR_DIS_OFFSET 1 +#define WRITE_LONG_CDB_COR_DIS_MASK 0x80 +#define WRITE_LONG_CDB_WR_UNCOR_OFFSET 1 +#define WRITE_LONG_CDB_WR_UNCOR_MASK 0x40 +#define WRITE_LONG_CDB_PBLOCK_OFFSET 1 +#define WRITE_LONG_CDB_PBLOCK_MASK 0x20 +#define WRITE_LONG_CDB_LBA_OFFSET 2 +/* SCSI ADDITIONAL SENSE Codes */ #define SCSI_ASC_NO_SENSE 0x00
@@ -871,7 +880,7 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,u8 spt_lut[8 ] = {0 ,0 ,2 ,1 ,4 ,6 ,5 ,7 };u8 grd_chk, app_chk, ref_chk, protect;u8 uask_sup =0x20 ; -u8 v_sup; +u8 v_sup, wrt_uncor, wu_sup, cd_sup;u8 luiclr =0x01 ; inq_response =kmalloc (EXTENDED_INQUIRY_DATA_PAGE_LENGTH ,GFP_KERNEL );
@@ -914,6 +923,10 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr, } id_ctrl = mem; v_sup = id_ctrl->vwc; + (id_ctrl->oncs &NVME_CTRL_ONCS_WRITE_UNCORRECTABLE ) ? + (wrt_uncor =0x01 ) : (wrt_uncor =0 ); + wu_sup = wrt_uncor <<3 ; + cd_sup = wrt_uncor <<2 ;memset (inq_response,0 ,EXTENDED_INQUIRY_DATA_PAGE_LENGTH ); inq_response[1 ] =INQ_EXTENDED_INQUIRY_DATA_PAGE ;/* Page Code */
@@ -921,7 +934,7 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr, inq_response[3 ] =0x3C ;/* Page Length LSB */ inq_response[4 ] = microcode | spt | grd_chk | app_chk | ref_chk; inq_response[5 ] = uask_sup; - inq_response[6 ] = v_sup; + inq_response[6 ] = wu_sup | cd_sup | v_sup; inq_response[7 ] = luiclr; inq_response[8 ] =0 ; inq_response[9 ] =0 ;
@@ -2916,6 +2929,51 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,return res; } +static int nvme_trans_write_long (struct nvme_ns *ns,struct sg_io_hdr *hdr, +u8 *cmd) +{ +int res =SNTI_TRANSLATION_SUCCESS ; +int nvme_sc; +struct nvme_command c; +u64 slba; +u8 cor_dis, wr_uncor, pblock; + + cor_dis =GET_U8_FROM_CDB (cmd,WRITE_LONG_CDB_COR_DIS_OFFSET ) & +WRITE_LONG_CDB_COR_DIS_MASK ; + wr_uncor =GET_U8_FROM_CDB (cmd,WRITE_LONG_CDB_WR_UNCOR_OFFSET ) & +WRITE_LONG_CDB_WR_UNCOR_MASK ; + pblock =GET_U8_FROM_CDB (cmd,WRITE_LONG_CDB_PBLOCK_OFFSET ) & +WRITE_LONG_CDB_PBLOCK_MASK ; + +if (!cor_dis || !wr_uncor || pblock) { + res =nvme_trans_completion (hdr,SAM_STAT_CHECK_CONDITION , +ILLEGAL_REQUEST , +SCSI_ASC_INVALID_CDB , +SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + goto out; + } + +if (cmd[0 ] ==WRITE_LONG ) + slba =GET_U32_FROM_CDB (cmd,WRITE_LONG_CDB_LBA_OFFSET ); +else + slba =GET_U64_FROM_CDB (cmd,WRITE_LONG_CDB_LBA_OFFSET ); + +memset (&c,0 ,sizeof (c)); + c.wu.opcode = nvme_cmd_write_uncor; + c.wu.nsid =cpu_to_le32 (ns->ns_id); + c.wu.slba =cpu_to_le64 (slba); + + nvme_sc =nvme_submit_io_cmd (ns->dev, ns, &c,NULL ); + res =nvme_trans_status_code (hdr, nvme_sc); +if (res) + goto out; +if (nvme_sc) + res = nvme_sc; + +out: +return res; +} +static int nvme_scsi_translate (struct nvme_ns *ns,struct sg_io_hdr *hdr) {u8 cmd[BLK_MAX_CDB ];
@@ -3001,6 +3059,10 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)case UNMAP : retcode =nvme_trans_unmap (ns, hdr, cmd);break ; +case WRITE_LONG : +case SERVICE_ACTION_OUT_16 : + retcode =nvme_trans_write_long (ns, hdr, cmd); +break ;default : out: retcode = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
include/uapi/linux/nvme.h +13 -0
@@ -310,6 +310,18 @@ struct nvme_dsm_range {__le64 slba; }; +struct nvme_write_uncor_cmd { +__u8 opcode; +__u8 flags; +__u16 command_id; +__le32 nsid; +__u32 rsvd2[8 ]; +__le64 slba; +__le16 nlb; +__u16 rsvd; +__u32 rsvd13[3 ]; +}; +/* Admin commands */ enum nvme_admin_opcode {
@@ -469,6 +481,7 @@ struct nvme_command {struct nvme_download_firmware dlfw;struct nvme_format_cmd format;struct nvme_dsm_cmd dsm; +struct nvme_write_uncor_cmd wu;struct nvme_abort_cmd abort; }; };
Signature · 1 line
1.8.3.2
PATCH v2 1/1 NVMe: write_long SCSI to NVMe translation implementation
Hi Keith,
Any comments/updates on this ?
Regards,
Sunad
-----Original Message-----
From: Linux-nvme [mailto:[email protected]] On Behalf Of Sunad Bhandary S
Sent: Tuesday, March 03, 2015 5:00 PM
To: linux-nvme at lists.infradead.org; keith.busch at intel.com
Cc: Sunad Bhandary S
Subject: [PATCHv2] NVMe: write_long SCSI to NVMe translation implementation
From: Sunad Bhandary S <[email protected]>
This patch implements the SCSI to NVMe translation for write_long. write_long is translated to the NVMe command write_uncorrectable as defined by the translation specification version 1.4.
This patch also indicates the device support for write_uncorrectable method in the response of extended inquiry as defined in the translation spec.
This patch is based on for-linus branch.
Changes:
v1 -> v2 : __le32 nlb field changed to __le16 nlb followed by __u16 rsvd.
--- drivers/block/nvme-scsi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++-- include/uapi/linux/nvme.h | 13 ++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-)
drivers/block/nvme-scsi.c index renamed from drivers/block/nvme-scsi.c +0 -0
e10196e..fa724cf 100644
drivers/block/nvme-scsi.c +0 -0
@@ -245,6 +245,15 @@ static int sg_version_num = 30534; /* 2 digits for each
component */
/* Report LUNs defines */
#define REPORT_LUNS_FIRST_LUN_OFFSET 8
+/*Write Long defines */
+#define WRITE_LONG_CDB_COR_DIS_OFFSET 1
+#define WRITE_LONG_CDB_COR_DIS_MASK 0x80
+#define WRITE_LONG_CDB_WR_UNCOR_OFFSET 1
+#define WRITE_LONG_CDB_WR_UNCOR_MASK 0x40
+#define WRITE_LONG_CDB_PBLOCK_OFFSET 1
+#define WRITE_LONG_CDB_PBLOCK_MASK 0x20
+#define WRITE_LONG_CDB_LBA_OFFSET 2
+
/* SCSI ADDITIONAL SENSE Codes */
#define SCSI_ASC_NO_SENSE 0x00
@@ -871,7 +880,7 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 spt_lut[8] = {0, 0, 2, 1, 4, 6, 5, 7};
u8 grd_chk, app_chk, ref_chk, protect;
u8 uask_sup = 0x20;
- u8 v_sup;
+ u8 v_sup, wrt_uncor, wu_sup, cd_sup;
u8 luiclr = 0x01;
inq_response = kmalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH,GFP_KERNEL); @@ -914,6 +923,10 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
}
id_ctrl = mem;
v_sup = id_ctrl->vwc;
+ (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) ?
+ (wrt_uncor = 0x01) : (wrt_uncor = 0);
+ wu_sup = wrt_uncor << 3;
+ cd_sup = wrt_uncor << 2;
memset(inq_response, 0, EXTENDED_INQUIRY_DATA_PAGE_LENGTH);
inq_response[1] = INQ_EXTENDED_INQUIRY_DATA_PAGE; /* Page Code */
@@ -921,7 +934,7 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
inq_response[3] = 0x3C; /* Page Length LSB */
inq_response[4] = microcode | spt | grd_chk | app_chk | ref_chk; inq_response[5] = uask_sup;
- inq_response[6] = v_sup;
+ inq_response[6] = wu_sup | cd_sup | v_sup;
inq_response[7] = luiclr;
inq_response[8] = 0;
inq_response[9] = 0;
@@ -2916,6 +2929,51 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,
return res;
}
+static int nvme_trans_write_long(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+ u8 *cmd)
+{
+ int res = SNTI_TRANSLATION_SUCCESS;
+ int nvme_sc;
+ struct nvme_command c;
+ u64 slba;
+ u8 cor_dis, wr_uncor, pblock;
+
+ cor_dis = GET_U8_FROM_CDB(cmd, WRITE_LONG_CDB_COR_DIS_OFFSET) &
+ WRITE_LONG_CDB_COR_DIS_MASK;
+ wr_uncor = GET_U8_FROM_CDB(cmd, WRITE_LONG_CDB_WR_UNCOR_OFFSET) &
+ WRITE_LONG_CDB_WR_UNCOR_MASK;
+ pblock = GET_U8_FROM_CDB(cmd, WRITE_LONG_CDB_PBLOCK_OFFSET) &
+ WRITE_LONG_CDB_PBLOCK_MASK;
+
+ if (!cor_dis || !wr_uncor || pblock) {
+ res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
+ ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_CDB,
+ SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
+ goto out;
+ }
+
+ if (cmd[0] == WRITE_LONG)
+ slba = GET_U32_FROM_CDB(cmd, WRITE_LONG_CDB_LBA_OFFSET);
+ else
+ slba = GET_U64_FROM_CDB(cmd, WRITE_LONG_CDB_LBA_OFFSET);
+
+ memset(&c, 0, sizeof(c));
+ c.wu.opcode = nvme_cmd_write_uncor;
+ c.wu.nsid = cpu_to_le32(ns->ns_id);
+ c.wu.slba = cpu_to_le64(slba);
+
+ nvme_sc = nvme_submit_io_cmd(ns->dev, ns, &c, NULL);
+ res = nvme_trans_status_code(hdr, nvme_sc);
+ if (res)
+ goto out;
+ if (nvme_sc)
+ res = nvme_sc;
+
+out:
+ return res;
+}
+
static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
{
u8 cmd[BLK_MAX_CDB];
@@ -3001,6 +3059,10 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
case UNMAP:
retcode = nvme_trans_unmap(ns, hdr, cmd);
break;
+ case WRITE_LONG:
+ case SERVICE_ACTION_OUT_16:
+ retcode = nvme_trans_write_long(ns, hdr, cmd);
+ break;
default:
out:
retcode = nvme_trans_completion(hdr,SAM_STAT_CHECK_CONDITION, diff --git a/include/uapi/linux/nvme.h b/include/uapi/linux/nvme.h index aef9a81..068db6d 100644
include/uapi/linux/nvme.h +13 -0
@@ -310,6 +310,18 @@ struct nvme_dsm_range {__le64 slba; }; +struct nvme_write_uncor_cmd { +__u8 opcode; +__u8 flags; +__u16 command_id; +__le32 nsid; +__u32 rsvd2[8 ]; +__le64 slba; +__le16 nlb; +__u16 rsvd; +__u32 rsvd13[3 ]; +}; +/* Admin commands */ enum nvme_admin_opcode {
@@ -469,6 +481,7 @@ struct nvme_command {struct nvme_download_firmware dlfw;struct nvme_format_cmd format;struct nvme_dsm_cmd dsm; +struct nvme_write_uncor_cmd wu;struct nvme_abort_cmd abort; }; };
--
1.8.3.2
_______________________________________________
Linux-nvme mailing list
Linux-nvme at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme
PATCH v2 1/1 NVMe: write_long SCSI to NVMe translation implementation
Review
Quoted 8 lines · Sunad Bhandary
Hi Keith,
Any comments/updates on this ?
(quoted diff) +2
-0id_ctrl = mem; v_sup = id_ctrl->vwc; + (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) ? + (wrt_uncor = 0x01) : (wrt_uncor = 0);
This is a weird way of writing it. Either do it like this:
if (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) wrt_uncor = 0x01; else wrt_uncor = 0;
Or this:
wrt_uncor = (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) ? 1 : 0;
(and what's with the 'hex for one, decimal for the other' decision you made there?)
Review static int nvme_scsi_translate(struct nvme_ns *ns, · line 3066
Quoted 9 lines
(quoted diff) +4
-0@@ -3001,6 +3059,10 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) case UNMAP: retcode = nvme_trans_unmap(ns, hdr, cmd); break; + case WRITE_LONG: + case SERVICE_ACTION_OUT_16: + retcode = nvme_trans_write_long(ns, hdr, cmd); + break;
Umm ... SAO16 can be used for more commands than just Write Long 16. You need to check the Service Action in addition to the opcode.
PATCH v2 1/1 NVMe: write_long SCSI to NVMe translation implementation
-----Original Message-----
From: Linux-nvme [mailto:[email protected]] On Behalf Of Matthew Wilcox
Sent: Tuesday, March 17, 2015 6:29 PM
To: Sunad Bhandary
Cc: keith.busch at intel.com; linux-nvme at lists.infradead.org
Subject: Re: [PATCHv2] NVMe: write_long SCSI to NVMe translation implementation
Quoted 5 lines
(quoted diff) +2
-0+ (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) ? + (wrt_uncor = 0x01) : (wrt_uncor = 0);This is a weird way of writing it. Either do it like this:
Quoted 8 lines
if (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) wrt_uncor = 0x01; else wrt_uncor = 0;Or this:
wrt_uncor = (id_ctrl->oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE) ? 1
: 0;
Quoted 1 line
(and what's with the 'hex for one, decimal for the other' decision you made
there?)
-There is nothing to the decision. I happened to pick up bits from the protect variable in the same function.
Quoted 6 lines
(quoted diff) +4
-0+ case WRITE_LONG: + case SERVICE_ACTION_OUT_16: + retcode = nvme_trans_write_long(ns, hdr, cmd); + break;Umm ... SAO16 can be used for more commands than just Write Long 16. You
need to check the Service Action in addition to the opcode.
I missed the part of SAO16 being used for other commands.
Currently there seems to be no SCSI macro defined for SOA16 corresponding to WRITE_LONG_16 or other commands. Any check for the service action out would have to be against hard coded value of 0x11(write_long_16).
_______________________________________________
Linux-nvme mailing list
Linux-nvme at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme
PATCH v2 1/1 NVMe: write_long SCSI to NVMe translation implementation
Quoted 5 lines
Quoted 4 lines
(quoted diff) +4
-0+ case WRITE_LONG: + case SERVICE_ACTION_OUT_16: + retcode = nvme_trans_write_long(ns, hdr, cmd); + break;
Quoted 8 lines
Quoted 1 line
Umm ... SAO16 can be used for more commands than just Write Long 16. You
need to check the Service Action in addition to the opcode.
I missed the part of SAO16 being used for other commands.
Currently there seems to be no SCSI macro defined for SOA16 corresponding to
WRITE_LONG_16or other commands. Any check for the service action out would have to be against hard coded value of 0x11(write_long_16).
Sounds good. The translation for SERVICE_ACTION_IN_16 in nvme-scsi.c decodes the SAI_READ_CAPACITY_16, so this isn't any different.
It's probably okay to add a define for SAO_WRITE_LONG_16 to include/scsi/scsi.h if you don't want to make it exclusive to nvme-scsi.
PATCH v2 1/1 NVMe: write_long SCSI to NVMe translation implementation
-----Original Message-----
From: Linux-nvme [mailto:[email protected]] On Behalf Of Busch, Keith
Sent: Wednesday, March 18, 2015 8:55 PM
To: Sunad Bhandary; 'Matthew Wilcox'
Cc: linux-nvme at lists.infradead.org
Subject: RE: [PATCHv2] NVMe: write_long SCSI to NVMe translation implementation
Quoted 9 lines
Quoted 7 lines
(quoted diff) +4
-0+ case WRITE_LONG: + case SERVICE_ACTION_OUT_16: + retcode = nvme_trans_write_long(ns, hdr, cmd); + break;Umm ... SAO16 can be used for more commands than just Write Long 16. You
need to check the Service Action in addition to the opcode.
Quoted 8 lines
I missed the part of SAO16 being used for other commands.
Currently there seems to be no SCSI macro defined for SOA16 corresponding to
WRITE_LONG_16or other commands. Any check for the service action out would have to be against hard coded value of 0x11(write_long_16).Sounds good. The translation for
SERVICE_ACTION_IN_16innvme-scsi.c
decodes the SAI_READ_CAPACITY_16, so this isn't any different.
Quoted 1 line
It's probably okay to add a define for
SAO_WRITE_LONG_16to
include/scsi/scsi.h if you don't want to make it exclusive to nvme-scsi.
Okay, I will make the changes for the SAO comparison for write_long_16 exclusive to nvme-scsi and send out the modified patch in a couple of days.
_______________________________________________
Linux-nvme mailing list
Linux-nvme at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme
A message that is not in the archive (sent off-list or not yet received): [email protected]
some questions about create I/O queues
Quoted 2 lines · dingxiang
When I create I/O queues and not create from qid 1,for example, I create from qid 3,then I insmod nvme driver, there will be some error information as below
How did you manage to create IO queues starting from QID 3 when the driver wasn't loaded?
some questions about create I/O queues
Quoted 8 lines · Keith Busch
Quoted 2 lines · dingxiang
When I create I/O queues and not create from qid 1,for example, I create from qid 3,then I insmod nvme driver, there will be some error information as below
How did you manage to create IO queues starting from QID 3 when the driver wasn't loaded?
HI,Keith
I have modified two places to create queues from QID 3 before the driver loaded,
details are as follows:
kernel version:3.10
nvme-core.c +2 -2
@@ -226,7 +226,7 @@ static void *cancel_cmdid(struct nvme_queue *nvmeq, int cmdid,struct nvme_queue *get_nvmeq (struct nvme_dev *dev) { -return dev->queues[get_cpu () +1 ]; +return dev->queues[3 ]; }void put_nvmeq (struct nvme_queue *nvmeq)
@@ -1703,7 +1703,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) q_depth =min_t (int,NVME_CAP_MQES (readq (&dev->bar->cap)) +1 ,NVME_Q_DEPTH ); -for (i =0 ; i < nr_io_queues; i++) { +for (i =2 ; i < nr_io_queues; i++) { dev->queues[i +1 ] =nvme_create_queue (dev, i +1 , q_depth, i);if (IS_ERR (dev->queues[i +1 ]))return PTR_ERR (dev->queues[i +1 ]);
Thanks !